LINUX.ORG.RU

Изучая Rust...

 , ,


1

4

Здравствуйте. Пытаюсь реализовать список на Rust. Вот что у меня получилось:

use std::fmt;

struct Node {
    value: i32,
    link: Option<Box<Node>>,
}

impl Node {
    fn new(value: i32) -> Node {
        Node { value: value, link: None, }
    }

    fn append(&mut self, value: i32) {
        match self.link {
            Some(ref mut node) => node.append(value),
            None => self.link = Some(Box::new(Node::new(value))),
        }
    }

    fn length(&self) -> i32 {
        match self.link {
            Some(ref node) => node.length() + 1,
            None => 1,
        }
    }

    fn insert_after(&mut self, value: i32, after: i32) -> bool {
        if self.value == after {
            self.link = Some(Box::new(Node { value: value, link: self.link.take() }));
            true
        }
        else {
            match self.link {
                Some(ref mut node) => node.insert_after(value, after),
                None => false,
            }
        }
    }
}

impl fmt::Display for Node {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.value)
        while
    }
}

fn main() {
    let mut stack = Node::new(1024);

     stack.append(67);

     println!("{}", stack);
}

Подскажите, как можно напечатать все элементы списка? В текущей реализации выводится только первый элемент.


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

Ага, именно поэтому статические анализаторы становятся всё сложнее.

Статические анализаторы не имеют отношения к выявлению unsafe.

Тебе не надо гарантировать валидность unsafe, как это пытаются делать статические анализаторы, а просто найти места в которых это используется. Т.е. сишные касты/голые указатели. Это делается 5минут.

Проверю не указатель, а наличие проверки:

Т.е. мне надо городить тонну дерьма - ок. Наговнякать это можно и в крестах.

Тем что Choice - это (boost) variant. В общем, есть контейнер содержащий variant. Надо обходить и обрабатывать.

Зачем там бустариант?

Да ладно? А опциональные значения?

А, т.е. уже всё съехало к тому, о чём говорил ранее - используемый NULL, ну дак - это проблема твой реализации - не используй его.

Ну и «анскил» - это тоже вполне объективная причина.

Да.

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

Я тебе в очередной раз говорю, вали из треда. Я задал вопрос в надежде получить ответ. А от тебя вижу только балабольство. И своим балабольством ты якобы пытаешься отговорить «зеленых адептов» учить Rust. Если же я ошибаюсь и мне это показалось - тем более вали из треда. Ты нигде не попытался ответить на заданный мною вопрос или помочь в изучении. Все, что ты написал это вода. Иди в другом месте письками меряться. Или это тут так принято показывать свою крутость и познания перед новичками такими вот вые...онами?

paret
() автор топика
Ответ на: комментарий от registrant27492

Мне тебе цитатку выкатить?

Выкати. Вижу следующее:

https://doc.rust-lang.org/book/lifetimes.html

Изучая Rust... (комментарий)

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

Изучая Rust... (комментарий)

...

Покажи какую стоимость имеют лайфтаймы.

Изучая Rust... (комментарий)

О чём тогда разговор, если не о лайфтаймах?

если лагика подразумевает, что объект неменяется, то он создаётся константой.

И как код, в который передают константную ссылку, может об этом знать?

И к расту это не имеет никакого отношения - это просто навязанная константность ничего не отличающая от обычной константности.

Где там навязанная константность?

Если это не raii, то никакого смысла в лайвтаймах нет, ибо всё просто копируется.

Тут я тебя не понимаю.

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

Вот зачем ты споришь о том чего не знаешь? Раст позволяет.

Зачем мне пародиная на unsafe, если я сам решаю где у меня safe, а где unsafe?

Затем чтобы явно декларировать намерения. Хотя бы для другие людей, если уж ты думаешь, что тебе лично такие «костыли» не понадобятся. Если не считаешь это аргументом, то спор можно сворачивать - смысла нет.

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

Тогда и вали из этой темы.

Отличная история.

Нет там рантайма! В core связка с компилятором.

Сомневаюсь, что тот набор икспертов, что ваяли раст осилил что-то вменяемо сделать.

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

registrant27492, дальше пиши _строго_ по делу. Тупняк будет удаляться. Отвечать на это сообщение не нужно.

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

Да и сомневаюсь я...

А ты возьми и посмотри, а потом спорь. Иначе это смешно выглядит.

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

о люди будут просто на автомате писать int x = void; вместо того, чтобы думать о наличии подходящего начального значения для x.

Я о людях лучшего мнения и надеюсь, что они «хотя бы» будут писать int x = 0. В любом случае, такая инициализация будет лучше в глаза бросаться.

B D интересное решение приняли - по умолчанию там всё инициализируется в дефолтное значение. Для флоатов/даблов - оно равно NaN. И в документации сетуют, что у интов нет такого «невалидного» значения которое помогало бы ошибки инициализации отлавливать.

А в расте uninitialized - unsafe.

Да еще такие, что различие в одном символе приводит к совершенно нехилой разнице в результатах:

Таких примеров в любом языке много придумать можно.

К оператору запятая претензия в том, что «обычный код» начинает делать нечто совсем неожиданное. Хотя согласен, что в какой-то мере это к перегрузке любых операторов относится.

Какой-то детский сад

Ну так предложи что-то другое - обсудим. Я сразу признал, что это всё мелочи и не я продолжаю про «детский сад» говорить.

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

Окай.
с поправкой на то, что свифт за тебя в хипе размещает, а в расте это явно делать надо

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

Т.е. сишные касты/голые указатели.

И что толку указатели искать если они используются как признак опциональности, например?

Наговнякать это можно и в крестах.

Не можно, а нужно. И в расте оно делается чуть удобнее и требуется, только и всего.

Зачем там бустариант?

Затем, что могут быть значения разных типов.

используемый NULL, ну дак - это проблема твой реализации - не используй его.

И что использовать вместо этого?

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

Или это тут так принято показывать свою крутость и познания перед новичками такими вот вые...онами?

К счастью, не у всех.

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

И что толку указатели искать если они используются как признак опциональности, например?

Чего?

Не можно, а нужно. И в расте оно делается чуть удобнее и требуется, только и всего.

Не нужно. Оно не делается удобно.

Затем, что могут быть значения разных типов.

Зачем нужны значения разных типов? Придумай простую задачу, который бы требовала их и которую ты считает соответствующей твой основной.

И что использовать вместо этого?

Ничего. Называй юзкейсы - я тебе расскажу как это делать без дерьма.

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

Я о людях лучшего мнения и надеюсь

А я нет. Когда общаешься с людьми на профильных форумах, то оказывается, что часть из собеседников — это реально очень крутые разработчики, с которыми тебе даже не тягаться. Остальная часть — балаболы, которые никогда не признаются, что программируют на весьма среднем уровне.

Тогда как вне форумов большинство разработчиков таковы, что кроме Java им особо-то в руки и давать ничего нельзя. И тут даже не в способностях конкретных людей дело, а в самой индустрии (в организации работы над проектами, подборе сотрудников, обучении и пр.). Тем более, когда в ИТ за деньгами пришло столько народу.

что они «хотя бы» будут писать int x = 0

Сейчас можно писать int x{}. И что, многие это делают? Те, кто думают про начальные значения — те используют, кто не думает, то даже и не знает про эту фичу.

Я сразу признал, что это всё мелочи и не я продолжаю про «детский сад» говорить.

Ну наше общение началось, если не ошибаюсь, вот отсюда. Мне не показалось, что вы признали там данный список претензий мелочами.

eao197 ★★★★★
()

Function overloading

Стал изучать Rust, и у меня вопрос: почему в нём нет перегрузки функций? В плюсах она превращается в кровавое месиво из-за неявных приведений типов, но в Расте-то нет неявных приведений типов. И типы аргументов однозначно определяют, какой из перегруженных вариантов нужно вызвать, безо всякой магии. Почему этого не сделали? «Пока не осилили», или принципиально против, потому что Программист Должен Страдать и Писать Много Кода Руками Вместо Того Чтобы За Него Это Делал Компилятор?

Ну ладно, вопрос попроще: почему даже значения по умолчанию для аргументов не сделали?

anonymous
()
Ответ на: Function overloading от anonymous

или принципиально против

Ага. Впрочем, на трейтах перегрузка есть.

почему даже значения по умолчанию для аргументов не сделали?

Вот тут есть RFC про именованные и опциональные аргументы и про переменное их количество. Почему не сделали хз. Предполагаю, что никому оно уж очень сильно не нужно, вот и откладывают.

DarkEld3r ★★★★★
()
Ответ на: Function overloading от anonymous

типы аргументов однозначно определяют, какой из перегруженных вариантов нужно вызвать, безо всякой магии. Почему этого не сделали?

Насколько я понимаю, в случае с выводом типов это не так просто.

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

Те, кто думают про начальные значения — те используют, кто не думает, то даже и не знает про эту фичу.

Дык, если их компилятор по рукам ударит, то придётся задуматься - узнаю и про {} и про void. Если выберут второе, то им же хуже.

Мне не показалось, что вы признали там данный список претензий мелочами.

Ну тогда признаю сейчас. (:

Вообще я как раз сторонник гибкости и возможностей, но с минимизированием случайного выстреливания в ногу. Раст не всегда хорош в первом, плюсы - во втором.

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

Насколько я понимаю, в случае с выводом типов это не так просто.

В Расте типы аргументов функции в обязательном порядке указываются, в чём проблема-то?

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

Ага. Впрочем, на трейтах перегрузка есть.

Ну если есть перегрузка по первому агрументу self, почему нельзя сделать по остальным?

Алсо, почитал дискуссию по ссылке - аргументация уровня «нинужно потамушто Зачем Если Можно Писать Много Boilerplate-Кода Руками Юзайте Чудесный Паттерн Builder». Раст и так лаконичностью не отличается, а тут уж совсем ява какая-то.

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

в чём проблема-то?

В том, что типы могут выводиться при передаче в функцию:

fn test_1(a: i32) {}
fn test_2(a: i8) {}

fn main() {
    let a = 10; // тип ещё не вывелся
    test_2(a); // a: i8
    test_1(a); // fail
}

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

Ну если есть перегрузка по первому агрументу self, почему нельзя сделать по остальным?

Хз. Отсутствие перегрузки - одна из тех вещей, которые изначально отталкивали от раста.

Алсо, почитал дискуссию по ссылке

Справедливости ради - идею не зарезали, а отложили. И аргументы там разные есть. Тоже считаю, что билдер - то ещё уродство. Да и в стандартной библиотеке мусора с дублированием функций в АПИ могло бы быть куда меньше.

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

В том, что типы могут выводиться при передаче в функцию:

Проблемы уровня борщехаскеля. Меня бы абсолютно устроило, если бы компилятор требовал, чтобы к моменту вызова перегруженной функции типы аргументов были однозначно определены.

anonymous
()
Ответ на: Function overloading от anonymous

И типы аргументов однозначно определяют, какой из перегруженных вариантов нужно вызвать

Например:

Ф( мут А, Б ) {}
Ф( А, мут Б ) {}

пусть а = Ф( мут, мут )
anonymous
()
Ответ на: комментарий от anonymous

Меня бы абсолютно устроило, если бы компилятор требовал, чтобы к моменту вызова перегруженной функции типы аргументов были однозначно определены.

Меня бы тоже.

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

Придумай простую задачу, который бы требовала их и которую ты считает соответствующей твой основной.

«Допустим», мы делаем текстовый редактор. На верхнем уровне у нас могут быть таблицы, параграфы, шейпы. В них, в свою очередь, могут разные раны - текст, номер страницы, картинка и т.д.

Называй юзкейсы - я тебе расскажу как это делать без дерьма.

«Допустим», есть свойства (для сущностей выше). Если какие-то свойства отсутствуют, то там лежит nullptr.

Или даже мы передаём опциональный параметер в функцию. Чем тут плох указатель?

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

«Допустим», есть свойства (для сущностей выше). Если какие-то свойства отсутствуют, то там лежит nullptr.

(просто компилябельный пример на С++17, без привязки к вашему обсуждению)

#include <experimental/optional>
#include <string>
using namespace std::experimental;
using namespace std;

struct Font {
    optional<bool>   bold;
    optional<bool>   italic;
    optional<string> family;
};

struct Text {
    optional<Font> font;
};

int main() {
    Text t;
    t.font = Font { true, {}, {} };
    
    const bool italic = t.font.value_or( false );
}
anonymous
()
Ответ на: комментарий от DarkEld3r

Или даже мы передаём опциональный параметер в функцию. Чем тут плох указатель?

Вот тем и плох - невалидным значением. Правда, если параметр нужно передавать по ссылке, то в Си++ выхода нет (по значению можно через optional, хотя это тоже на ADT).

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

компилябельный
const bool italic = t.font.value_or( false );

Соврал, вот компилябельный:

const bool italic = t.font.value_or( Font() ).italic.value_or( false );
anonymous
()
Ответ на: комментарий от anonymous

(просто компилябельный пример на С++17, без привязки к вашему обсуждению)

У многих сущностей могут быть одинаковые свойства. Для экономии памяти они (если есть) лежат в «хранилище свойств» по шаред поинтеру. Потому и не optional.

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

Вот тем и плох - невалидным значением.

Так оно «валидное».

Ну и ты сам понимаешь, что optional в плюсах имеет такие же проблемы.

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

optional в плюсах имеет такие же проблемы

optional в плюсах имеет похожие проблемы. Но по крайней мере у него есть метод value_or и он генерирует исключение, а не сегфолт,

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

Ну и ты сам понимаешь, что optional в плюсах имеет такие же проблемы.

Нет. Optional ты не можешь разыменовать, пока не проверишь на валидность.

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

Но по крайней мере у него есть метод value_or и он генерирует исключение, а не сегфолт,

Насколько старая вот тут информация?

This operator does not check whether the optional contains a value. If checked access is needed, value() or value_or() may be used.

В бусте, вроде, используются асерты. Проверять сейчас лень.

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

Ну, сделали.так. Метод value бросает исключение - это лучше сегфолта, но ненамного.

Без оператора match на уровне языка лучше не сделаешь.

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

Насколько старая вот тут информация?

UB может быть и запуском исключения. Я знаком только с реализацией из cxxomfort - она делает именно так. Думаю, любая реализация, написанная не наркоманами, тоже бросает исключение.

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

У многих сущностей могут быть одинаковые свойства. Для экономии памяти они (если есть) лежат в «хранилище свойств» по шаред поинтеру. Потому и не optional.

А ты мерял экономию - сколько она даст на общем фоне? Вряд-ли она будет вообще заметна. Во-вторых - шаред поинтеры это хорошо, но если уж экономить и при этом делать прямо, то надо использовать интрузивные указатели, и шарить не экземпляры класса, а данные под этими экземплярами, чтоб не выпячивать указатели, хоть и умные, наружу. Так сделано, например, в Qt для многих классов.

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

Думаю, любая реализация, написанная не наркоманами, тоже бросает исключение.

Вот не уверен... Ну или наркоманов много оказывается.

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

А ты мерял экономию - сколько она даст на общем фоне?

Да. Даст достаточно.

чтоб не выпячивать указатели

И что это даст?

Так сделано, например, в Qt для многих классов.

Ты про их «D-Pointer»? Так у него задача несколько другая, по крайней мере, по их аргументации. Или про CoW?

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

Да. Даст достаточно.

Да ну, если стили, например, логично шарить как единую сущность, которая применяется к разным частям текста (и меняет их всех), если логично использовать CoW, чтоб не следить вообще за кодом, то вручную шарить отдельные их части исключительно для экономии памяти - смысла мало и даже вредно, ну выиграешь ты несколько Кб на документе - кто это заметит?

И что это даст?

struct Font {
    shared_ptr<String> family; // sizeof - 2 указателя
};

Font f = parentFont();
if( f.family ) s = *f.family; // Забудем проверку - креш
f.family->append( "!" ); // Опс, мы забыли скопировать себе копию и похерили шрифт во всей программе

Или:

struct Font {
    QString family; // sizeof - 1 указатель
};

Font f = parentFont();
if( !f.family.isNull() ) s = f.family; // Все норм, забыли проверку - получили пустую строку
f.family.append( "!" ); // Все норм, шрифт у родителя не изменился, мы создали копию

Ты про их «D-Pointer»? Так у него задача несколько другая, по крайней мере, по их аргументации. Или про CoW?

Про CoW.

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

Да ну

Ну да. Свойства - это не просто несколько булевских флажков (на самом деле, даже optional<bool>), хотя и их изрядно получается. Это ещё и ещё и цвет текста/бекграунда (и нет, цвет - это не тупо RGBA) и шрифт и много другой фигни.

Собственно, свойства между стилями тоже шарятся.

Два указателя или один указатель - не суть важно, всё равно в итоге памяти столько же потратится. Тем более, что в твоём примере теряется «не заданное» состояние. Будешь ещё в optional заворачивать? Молча получать пустое значение как раз нафиг не нужно.

И да, «выпячивать указатели» удобно - свойства могут задаваться на разных уровнях. В итоге резолвинг выглядит как-то так: берём дефолтные свойства и проходимся по «уровням» и если свойство имеется - заменяем.

Про CoW.

Редактирование - это отдельная большая тема. Хинт: совместное редактирование.

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

Это ещё и ещё и цвет текста/бекграунда (и нет, цвет - это не тупо RGBA) и шрифт и много другой фигни.

Запусти профайлер и убедись, что создание этих свойств по затратам где-то в жопе на самом дне, и что все упирается в метрики шрифтов, I/O, алгоритмы по лайауту, и собс-но отрисовку. И даже больше, возьмем, например, QColor, он не шарит под собой данные, и умеет не только RGBA плюс «пустое значение»:

    {
        QColor ac = a;
    },
    10000000 );

    bench( "Copy shared_ptr<QColor>", [&]
    {
        std::shared_ptr<QColor> bc = b;
    },
    10000000 );
[/cpp]

Copy QColor: 359ms
Copy shared_ptr<QColor>: 683ms

А знаешь почему? Потому-что QColor копируется как блок памяти, и удаляется как блок памяти, а shared_ptr - это атомарный счетчик + копирование блока памяти + косвенная обращение по указателю к этому счетчику. Точно так же будет и с optional<bool>, который сам по себе прост как два байта (и является двумя байтами) и т.д. Не там и не так ты экономишь память и оптимизируешь. Повторюсь, есть смысл шарить стиль как нечто общее, есть смысл использовать CoW для строк, стилей и т.д., и нет ровно никакого смысла руками заворачивать в shared_ptr отдельные поля у шрифтов, стилей и пр. Это пессимизация кода.

Тем более, что в твоём примере теряется «не заданное» состояние.

Нет, ты просто невнимателен, там есть isNull, QString() - это не заданное состояние, а QString("") - пустая строка.

Редактирование - это отдельная большая тема. Хинт: совместное редактирование.

Совпадение, мой теперешний проект - совместное редактирование, правда не только и не сколько текста. И это действительно большая и сложная тема. Потому я сразу выписал пару библиотек, одна - для создания описаний общих данных и работы с ними на JS, C++, Python etc., вторая - для хранения и синхронизации этих данных. А основной код пишется ровно так же как на обычном Qt, например. Единственное что мне приходится делать - я выписываю загрузку/создание верхнего объекта (проекта) и задаю транзакции. А синхронизировать добавления, изменения, удаления и пр. это уже не мои проблемы. И как ты живешь с shared_ptr - я не представляю.

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

Поломанный пример:

    QColor a;
    std::shared_ptr<QColor> b = std::make_shared<QColor>( "#FFFFFF" );

    bench( "Copy QColor", closure( [&]
    {
        QColor ac = a;
    } ),
    10000000 );

    bench( "Copy shared_ptr<QColor>", closure( [&]
    {
        std::shared_ptr<QColor> bc = b;
    } ),
    10000000 );
anonymous
()
Ответ на: комментарий от DarkEld3r

И да, «выпячивать указатели» удобно - свойства могут задаваться на разных уровнях. В итоге резолвинг выглядит как-то так: берём дефолтные свойства и проходимся по «уровням» и если свойство имеется - заменяем.

И зачем тут выпячивание указателя? Код с CoW будет выглядеть ровно точно так же.

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

П.С. если что это просто пример проверки состояния, ес-но искать нужно сверху-вниз и сразу брякнуться

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

Запусти профайлер и убедись, что создание этих свойств по затратам...

«Затраты» - это у тебя память? Потому что мы говорили именно о ней.

И ты серьёзно думаешь, что ничего не измерялось и тут ты такой прибегаешь и предлагаешь «решение всех проблем»? Причём тут вообще «бенчкарки» какой-то фигни типа QColor. Я и не предлагал такие мелкие сущности шарить. Шарятся параграф и ран пропсы целиком.

и нет ровно никакого смысла руками заворачивать в shared_ptr отдельные поля у шрифтов, стилей и пр.

Естественно, но такого я и не утверждал. Ок, пусть это было недопонимание.

Но я всё равно не понимаю нафига ты CoW впариваешь. Если мы загружаем свойства стилей, параграфов, ранов и т.д. То как тут CoW поможет, если мы не будем «руками» объединять одинаковые свойства?

Нет, ты просто невнимателен, там есть isNull

Да, тут ты прав. Но тогда я тем более не понимаю что твой предыдущий пример должен был показать. Выступаешь против расшивания мелких сущностей и при этом предлагаешь использовать QString с CoW внутри. Зачем?

DarkEld3r ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.