Comments 36
Я понимаю, что речь идет исключительно о вре́менном даунгрейде &mut до &. Однако, не знакомый с Rust человек может подумать, что это обычное использование неконстантных объектов в константном контексте.
Имхо, этот момент стоило бы пояснить подробнее.
Я бы написал «не может пережить».
Люблю картинки)
Не видел этот пример, так что не скажу почему автор написал именно так, но никто не запрещает создать строку напрямую:
let mut abc = String::new();
Это будет действительно немножко эффективнее чем инициализация пустой строкой:
let mut abc = String::from("");
Но может автор хотел заодно показать этим примером, как можно создать не только пустые строки, но и с заданным текстом.
Если очень сильно заботится о производительности, то можно предположить сколько текста будет на входе и выделить память заранее:
let mut abc = String::with_capacity(10);
А что в rust не бывает null?
Вместо него есть Option с гораздо более явной семмантикой, чем null.
сделай ссылку на нулевой указатель
let a: *const i32 = std::ptr::null();
let b: &*const i32 = &a;
но это вообще несколько другое.
Собственно null — это одновременно великая и ужасная вещь. Именно когда разработчики Java «сдались» и сделали так, что обьявлять возможность кидания NullPointerException стало не нужно вся хвалёная «безопасность» «свернулась в трубочку и стекла на пол». Я не видел ни одной программы на Java сколько-нибудь приличного размера, которая бы не падала из-за того, что кто-то где-то таки кинул NPE и он бы не улетел далеко за пределы того модуля где был порождён (он может быть пойман и завёрнут в пять обёрток, но сути это не меняет).
Сможет ли эту проблему решить rust — неизвестно, пока на нём программ в миллионы строк никто не писал. Но попытка достойная.
Как оно будет на практике — посмотрим.
К аргументу khim добавлю, что этот get
(на самом деле, unwrap
) придётся писать, а это дополнительные телодвижения и это хорошо. Сразу приходится задумываться: а может тут не unwrap
нужен, а например unwrap_or
.
А как вы планируете избавляться от null в джаве?Я не предлагаю от него избавляться. Я предлагаю избавляться от Java. Ибо все преимущества ради которых заплатили весьма и весьма немалую цену оказались «пшиком». Безопасности нет, переносимости нет, для того, чтобы получить приличную скорость нужно, фактически, реализовывать «своё» управление памятью, размещая обьекты в массивах и самостоятельно отмечая — где живые, где мёртвые.
При этом ещё и варианта сделать как в большинстве скриптовых языков («выйти» в C и там всё реализовать эффективно) — в общем тоже нет, так как JNI — штука весьма и весьма своенравная и не очень эффективная.
Нет, сборщик мусора, он же управитель памятью, сделает вам пустой объект, где все ссылки забиты null-ами и дальше уже на этапе инициализации они будут переписываться на верные значения.И это — очередное 100500е место, где сборщик мусора мешает сделать нормальный язык. Возникает вопрос: а оно точно надо? Мы точно получаем выигрыш из-за того, что не используем разного рода scoped_ptr'ы или shared_ptr'ы, а используем «модный» «полноценный» сборщик мусора?
Обидно то, что мы теперь с этим убожеством связаны на многие годы, так как эта каракатица поселилась в самом сердце Android'а…
А пруфы есть? Система типов java, насколько я помню, не слишком-то и sound, и вряд ли надстройка способна это изменить
Никто не спорит с тем, что поверх Java-машины можно водрузить всё, что душе угодно (в качестве безумного варианта: водрузите JPC поверх вашей JVM — и получите любой язык, с любыми свойствами), но вот сохранить при этом совместимость с Java — уже не получится. Или — или, на выбор.
Ссылки — это инструмент контролирующий совместный доступ к памяти, поэтому null для ссылки — в принципе лишён смысла.
Если нет переменной, то не нужна и ссылка.
При этом неинициализированные переменные (заранее объявленные) вполне допустимы, компилятор контролирует порядок исполнения и не даст скомпилировать код, читающий переменную до инициализации.
Другой момент — каждый раз создавать строку в процессе преобразований — не самый эффективный паттерн, хотя, конечно, так можно (например, функция будет каждый раз создавать String и возвращать её).
Но для ввода-вывода API строится так, что пользователь сам создаёт буфер и передаёт его для заполнения в функцию. Кроме прочего, это позволяет реализовывать эффективную конкатенацию и в случае необходимости переиспользовать буфер, без повторного выделения памяти в куче (достаточно «дорогая» операция).
При этом буфер может быть произвольного типа, лишь бы он реализовал соответствующий необходимый типаж Read или Write.
При таком подходе весь контроль над тем, что на самом деле будет происходить, — в руках программиста. И это достаточно важно для языка, предназначенного быть эффективным и позиционируемого как низкоуровневый/системный.
Может https://docs.rs/text_io или https://docs.rs/scan_fmt (или еще что похожее) взять?
Не спец по Rust, но то что копирование или перемещение зависит от типа при сходных действиях, мне очень не нравится ибо смотря на выражение let a = b я не уверен что произойдет c переменными a и b.
На ранних стадиях развития языка с явной семантикой перемещения экспериментировали, но в итоге пришли к текущей схеме
https://www.reddit.com/r/rust/comments/2x0wq0/did_rust_ever_experiment_with_making_moves
смотря на выражение let a = b я не уверен что произойдет c переменными a и bНу почему же? Ясно что окажется в
a
, а вот останется ли что-нибудь в b
— уже не так ясно, но это и не очень страшно: если обьект простой и копируемый, то его ненужную копию «изведёт» оптимизатор, а если сложный — и некопируемый, то попытка его использовать — это ошибка, компилятор вам не даст ничего напутать. Проблема будет если обьект копируемый, но сложный и его копировать дорого — так просто лучше не делать.
Графическое описание владения и заимствования в Rust