LINUX.ORG.RU

Я познаю Rust: Лайфтаймы

 ,


2

5

Пытаюсь разобраться как работать с лайфтаймами:

use std::collections::LinkedList;

struct Point {
    x: f32,
    y: f32,
}

struct Rectangle<'a> {
    p2: &'a Point,
    p1: &'a Point,
}

fn main() {
    let mut list = LinkedList::new();
    let point1 = Point { x: 0.3, y: 0.4 };
    let point2 = Point { x: 0.3, y: 0.4 };
    
    let rect = Rectangle { p1:&point1, p2:&point2};
    list.push_back(rect);
    list.clear();
}

Как правильно очищать список, чтобы компилятор не ругался на point1, point2?

★★★★★

Ответ на: комментарий от dave

Очень сложно. Чтобы сделать простую связь Article-Comments, нужно гуглить из текущей документации непонятно как это делать. Как это принято делать в обычных ЯП - не компилится. Большая часть примеров на int32, а не на использовании объектов и коллекций с объектами. А для раста, насколько я сейчас понял, в последнем случае другой код нужно писать.

foror ★★★★★
() автор топика
Последнее исправление: foror (всего исправлений: 6)
Ответ на: комментарий от dave

Нет, в The Book все понятно обяснено. Первым обявлен — последним уничтожен. Ссылки на значения не должны висеть в воздухе, значит они должны быть объявлены позже тех значений, на которые ссылаются. Здесь list содержит ссылки на point1 и point2, стало быть, он должен быть объявлен позже.

anonymous
()
Ответ на: комментарий от foror

А что сложно? Если в расте дается новая сущность Borrow Checker то естественно нужно прочитать, как она работает. Owernship, Borrowing и Lifetimes — вот все что нужно изучить, остальное все есть в других популярных языках, хоть и не все в плюсах. Кстати, вышеперечисленное есть и в плюсах, просто там этому никто должного внимания не уделяет. В расте наложены дополнительные ограничения, потому просто так представить как это работает из знания плюсов нельзя. Нужно таки прочитать, как это работает в Rust.

anonymous
()
Ответ на: комментарий от anonymous

Думаю вопрос был совсем про другое, про то, что программисту нужно уделять внимание подобным мелочам. Хотя наверное со временем привыкаешь. Или может IDE за тебя правильно переставит.

foror ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Да всё может и просто. Но мне удобнее когда есть примеры из реального мира, а не куча слов и надуманные примеры.

foror ★★★★★
() автор топика
Последнее исправление: foror (всего исправлений: 1)
Ответ на: комментарий от dave

А не слишком сложно?

Ровно настолько же сложно, как в Си++ и Си, но проверяется транслятором.

tailgunner ★★★★★
()
Ответ на: комментарий от foror

А что вы хотели от системного програмирования? По сравнению с C/C++ - в rust намного меньше писанины в десятки раз меньше способов выстрелить себе в ногу.

RazrFalcon ★★★★★
()
Ответ на: комментарий от tailgunner

По сравнению с Си++ - просто меньше.

Возьмем пример от ТС:

let mut list = LinkedList::new();
let rect = Rectangle { p1:&point1, p2:&point2};
list.push_back(rect);

в С++ запишется это как:

list<Rectangle> l({ point1, point2 });
anonymous
()
Ответ на: комментарий от anonymous

Точнее так:

list<Rectangle> l {{ point1, point2 }};

В общем всякие ::new() и push_back для начального заполнения списка уйдут. Вообще, если смотреть код на Rust - обычно он далеко не лаконичен и перегружен.

anonymous
()
Ответ на: комментарий от anonymous

А, извини, случайно удалил абзац. Вот по этой: параллельность в расте (комментарий)

В общем всякие ::new() и push_back для начального заполнения списка уйдут

Ты сэкономил одну строку на учебном пример.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

А, извини, случайно удалил абзац. Вот по этой: параллельность в расте (комментарий)

В данном случае я возьму tbb::parallel_for и сэкономлю не только в строках, но и в сложности. И получу лучшую производительность.

anonymous
()
Ответ на: комментарий от anonymous

Вообще, если смотреть код на Rust - обычно он далеко не лаконичен и перегружен.

О да. Плюсовые итераторы верх лаконичности.

std::vector<int> vec({1, 2, 3, 4});
auto it = std::find_if(vec.begin(), vec.end(), [](int i){
    return i % 2 == 0;
});

if (it != vec.end()) {
    std::cout << *it << std::endl;
}

vs

let vec = vec![1, 2, 3, 4];
if let Some(v) = vec.iter().find(|i| *i % 2 == 0) {
    println!("{}", v);
}

RazrFalcon ★★★★★
()
Ответ на: комментарий от anonymous

И получу лучшую производительность.

Лучшую производительность на списке из двух элементов?

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Но в расте хранится ссылка, а не объект.

Конкретно в данном примере и типах можно ссылки спокойно выкинуть. Кроме того ты же будешь работу со строками на Rust через указатели делать, если тебе предложат написать аналог сишного кода?

anonymous
()
Ответ на: комментарий от anonymous

Конкретно в данном примере и типах можно ссылки спокойно выкинуть.

Вы же понимаете, что пример на то и пример, что в нём можно опустить детали.

Кроме того ты же будешь работу со строками на Rust через указатели делать, если тебе предложат написать аналог сишного кода?

Можно пример такого кода?

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

О да. Плюсовые итераторы верх лаконичности.

Не итераторы, а библиотека алгоритмов. Поверх итераторов можно точно так же сделать компактный в использовании find, который будет возвращать optional. Но его нет, тут я не спорю, и потому многие либо имеют свою библиотеку, либо берут чужую. С этим минусом спорить не буду. Хотя что-то в С++2х обещают, но то будет видно.

anonymous
()
Ответ на: комментарий от tailgunner

Ну так возьми. Покажи код.

Там показывать нечего, все сведется к вызову данной функции поверх calc_rows. А полный пример переводить на С++ у меня желания нет.

anonymous
()
Ответ на: комментарий от RazrFalcon

Можно пример такого кода?

Работы на С со строками? Ну например:

#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}
anonymous
()
Ответ на: комментарий от anonymous

То есть мы изначально подразумеваем, что у нас однобайтная кодировка, так?

Вот пример с нормальным UTF-8.

let text = "- This, a sample string.";
let iter = text.split(|c| match c {
    ' ' | ',' | '.' | '-' => true,
    _ => false,
}).filter(|s| !s.is_empty());

for part in iter {
    println!("{}", part);
}
[/rust]

RazrFalcon ★★★★★
()
Ответ на: комментарий от anonymous

Ну если тебе будет легче:

Конечно. Увидеть простое «сделать_зашибись()» в дискуссии о краткости - это как бы намекает.

tailgunner ★★★★★
()
Ответ на: комментарий от RazrFalcon

Вот пример с нормальным UTF-8.

Но тут же нет указателей. Это совершенно другой пример (если что это на тему выкинутых ссылок в С++ коде).

anonymous
()
Ответ на: комментарий от anonymous

А в rust и нет указателей в понимании С. Зачем они там?

Зачем мне писать на rust в стиле C?

Это совершенно другой пример

Результат тот же, какие проблемы?

RazrFalcon ★★★★★
()
Последнее исправление: RazrFalcon (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Конечно. Увидеть простое «сделать_зашибись()» в дискуссии о краткости - это как бы намекает.

Окей:

RgbImage make_pic_3th( uint32_t width, uint32_t height) {
    ImageBuffer pic(width, height);

    vector<thread> workers;
    const int max_step = 3;
    for( int i = 0 ; i < max_step; ++i )
        max_step.emplace_back( calc_rows, i, max_step, width, height, ppic );
    
    for( auto& th : workers )
        th.join();

    return pic;
}

За правильность не ручаюсь, но как-то так.

anonymous
()
Ответ на: комментарий от RazrFalcon

Зачем мне писать на rust в стиле C?

Точно так же в коде на С++ не было никакого смысла лепить ссылки.

anonymous
()
Ответ на: комментарий от anonymous

Плохо тут только одному.

Вы привели код, который работает по-другому (нужно хранить ссылку, а не объект). Я привёл код, который работает идентично (нужно разбивать строку на подстроки без выделения памяти).

RazrFalcon ★★★★★
()
Ответ на: комментарий от kirk_johnson

То есть несмотря на то, что я уже очистил список, и с точки зрения человеческой логики все ок, rust не осиливает и вопит про ошибки?

На самом деле такое поведение можно реализовать. Для этого clear должен забирать владение. Но тогда такой код не будет работать:

let v = Vec::new();
v.push(1);
v.clear();
v.push(1); // error, object moved

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Вы привели код, который работает по-другому (нужно хранить ссылку, а не объект). Я привёл код, который работает идентично (нужно разбивать строку на подстроки без выделения памяти).

Херня, это другой код, с указателями можно сделать больше:

/* strtok example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] ="- This, a PREF:sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%ld: %s\n", pch-str, pch);
    
    if( *pch == 'T' )
        *pch = 't';
    
    if( !strcmp( pch, "a" ) )
        pch = strtok (pch + 7, " ,.-");
    else
        pch = strtok (NULL, " ,.-");
  }
  return 0;
}
anonymous
()
Ответ на: комментарий от anonymous

Херня, это другой код, с указателями можно сделать больше:

Да и с strtok тоже. В общем смысл как раз в том, что идентичный код писать смысла нет, как и придираться - а у вас тут ссылок нет, а у вас то, а у вас се. Работает - значит работает. А детали реализации это побочное, может понадобиться, а может и нет.

anonymous
()
Ответ на: комментарий от RazrFalcon

let vec = vec![1, 2, 3, 4];
if let Some(v) = vec.iter().find(|i| *i % 2 == 0) {
println!(«{}», v);
}

По большому счету это напоминает попытку подсчитать синтаксический оверхед (с). Ничто не мешает на C++ записать так:

std::vector<int> v{ 1, 2, 3, 4 };
auto r = ranges::find_if( v, [](int i) { return i % 2 == 0; });
if( r != end(v) )
	fmt::print( "{}\n", *r );
Количество приседаний, которые нужно сделать в C++ и в Rust-е одинаково. И говорить о многословности C++ на основе того, что в C++ нужно писать template и typename там, где в Rust-е можно обойтись лишь угловыми скобочками — это прям детский сад какой-то. Тогда уж нужно сразу сравнивать double и f64.

eao197 ★★★★★
()
Последнее исправление: eao197 (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Ой, прассыте, я не знал, что в сравнении на многословность должна использоваться только стандартная библиотека.

PS. У тебя дурочка уже включена на постоянке, так же, как и генератор желчи?

eao197 ★★★★★
()
Ответ на: комментарий от tailgunner

Дядя Вася, ты дурак? Если ты думаешь, что тебе написали очередной «сделать_зашибись()», который даже не скомпилируется, то попробуй сам, если мозги еще желчью не растворились: https://bitbucket.org/eao197/lor_cpp_example_range_fmt

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Дядя Вася, ты дурак?

Не-а. Я умный. И иногда даже спкойный %)

Если ты думаешь, что тебе написали очередной «сделать_зашибись()»

Я так не думаю. Но, если не нужно быть в теме последней моды Си++ (а мне это не нужно), пользы в примерах с использованием левых библиотек - не больше, чем в «сделать_зашибись()»

Проверялось с gcc-5.4.0.

Как попробовать

Поставить Ruby, поставить Mxx_ru: gem install Mxx_ru.

Thanks but no thanks, как говорится.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Но, если не нужно быть в теме последней моды Си++

Ну если ты тормозишь на C++ 10 летней давности, то давай тамошний C++ сравнивать с тамошним Rust-ом. Что, Rust-а тогда не было? Ба, да как же так-то? Или тебе приятно сравнивать _современный_ Rust с древним C++? Тогда зачем ограничиваться C++98, можно и самый первый C++ вспомнить. Разрыв будет еще значительнее.

Thanks but no thanks, как говорится.

Ну вот нет в C++ такого же стандарта, как Cargo в Rust-е, приходится выкручиваться. Но пример был приведен для того, чтобы ты увидел, что пример компилируется и работает.

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

Херня, это другой код, с указателями можно сделать больше:

Ага. При условии, что кодировка однобитная. Но кого это волнует.

RazrFalcon ★★★★★
()
Ответ на: комментарий от anonymous

Работает - значит работает.

Только не тогда, когда задача состоит в том, чтобы хранить указатель на объект, а не сам объект, в структуре.

RazrFalcon ★★★★★
()
Ответ на: комментарий от eao197

Ничто не мешает на C++ записать так:

Ага. Кроме как наличие C++14 компилятора. Я хз какой набор фич поддерживается в C++11 режиме.

Количество приседаний, которые нужно сделать в C++ и в Rust-е одинаково.

Ловко вы. Подключить внешнюю либу, которая работает с 2.5 компиляторами, чтобы убрать begin()/end().

И говорить о многословности C++ на основе того, что в C++ нужно писать template и typename там, где в Rust-е можно обойтись лишь угловыми скобочками — это прям детский сад какой-то.

Шта? Какой «template и typename»? Об этом вообще речи не было.

RazrFalcon ★★★★★
()
Ответ на: комментарий от RazrFalcon

Количество приседаний, которые нужно сделать в C++ и в Rust-е одинаково
Подключить внешнюю либу

Вот даже на этом этапе уже не одинаково :)

mersinvald ★★★★★
()
Последнее исправление: mersinvald (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.