Panzerschrek[CN]
> Потому, что Rust - бойлерплейтное говно, в котором надо руками звать в таком
> случае фабричую функцию (default) и заниматься прочим онанизмом с
> взятием/разыменованием указателей, заворачиванием значений в optional и т. д.
При этом в крестах тоже у многих классов как раз родной конструктор приватный, а наружу выставляются статические методы, создающие объект.
Что касается проставки ссылок, то это как раз хорошо, что при чтении foo(&mut a) ты точно видишь, что объект a реально будет меняться.
1 frag / 2 deaths
> При этом в крестах тоже у многих классов как раз родной конструктор приватный,
> а наружу выставляются статические методы, создающие объект.
Это используют в хитрых случаях, когда создание объекта может не удастся (чтобы вернуть nullptr/nullopt), или когда используется дедупликация/кеширование объектов.
Но блин, для векторов и строк писать вручную Vec::new() и String::new() - это перебор.
> Что касается проставки ссылок, то это как раз хорошо, что при чтении foo(&mut
> a) ты точно видишь, что объект a реально будет меняться.
Да, есть такое. Но на практике это не сильно часто. Ибо в нормальном коде сама по себе передача в функцию изменяемой ссылки (кроме this) - штука весьма редкая.
Panzerschrek[CN]
> Это используют в хитрых случаях, когда создание объекта может не удастся (чтобы
> вернуть nullptr/nullopt), или когда используется дедупликация/кеширование
> объектов.
Либо когда нужны конструкторы с неотличимыми наборами параметров, но делающие разные вещи.
Panzerschrek[CN]
> Но блин, для векторов и строк писать вручную Vec::new() и String::new() - это
> перебор.
Ну, возможно для дефуальтных нет смысла заставлять писать...
1 frag / 2 deaths
> Ну, возможно для дефуальтных нет смысла заставлять писать...
Так вроде можно и не писать:
let mut s = default(); // the rest of the code
Разве нет?
Имбирная Ведьмочка
> let mut s = default();
А в Ü это просто
var SomeType mut variable_name;
А для полей просто
SomeType field_name;
Имбирная Ведьмочка
> let mut s = default();
let mut s: Vec;
не, недостаточно?
1 frag / 2 deaths
> let mut s: Vec;
> не, недостаточно?
Ну допустим даже, что мы взяли и определили, вопреки всей логике, что let mut s: T это на самом деле let mut s = default() as T.
И как теперь тогда объявлять переменные, которые специально должны быть изначально пустыми?
Panzerschrek[CN]
> Ну допустим, памяти нету. Тогда конструктор это функция описания шагов
> конструирования объекта.
Ёрничаешь?
Ну, допустим, так оно и есть. T::new() - это функция описания шагов конструирования T. Оказывается, кострукторы всё это время были среди нас, а мы и не подозревали. И на что тогда жаловаться, если всё уже сделано?
Panzerschrek[CN]
> var SomeType mut variable_name;
Вообще-то, твой вариант не проще - в оригинале тип не указывается.
Panzerschrek[CN]
> А для полей просто
> SomeType field_name;
#[derive(Default)]
Или даже вот.
Имбирная Ведьмочка
> И как теперь тогда объявлять переменные, которые специально должны быть изначально пустыми?
Компилятор Rust статически таки да, умеет отложенно инициализировать переменные и следит за тем, чтобы инициализированными они были всегда. Но по факту такую штуку лучше убрать и сделать инициализацию через выражения, возвращаемые связкой if-else.
> Ну, допустим, так оно и есть. T::new() - это функция описания шагов конструирования T. Оказывается, кострукторы всё это время были среди нас, а мы и не подозревали.
Конструктор на то и конструктор, что компилятор знает о его специальном значении, и посему умеет вызывать его когда надо.
Например, в крестах:
std::string a("foo"), b( a), c( 64, 'Q'), d( );
Здесь компилятор вызывает разные конструкторы класса, выбирая нужный, в зависимости от переданных аргументах.
В ущербном Rust же придётся вспоминать, как называется каждая функция и вызывать её по имени:
let a = String::from("foo"); let b = a.clone(); let c = String::construct_with_n_values(64, 'Q'); let d = String::default();
А ещё в этом варианте могут быть сюрпризы, когда статическая функция класса не является фабричной и вызов SomeClass::some_function() возвращает что-то другое, а не новосозданный экземпляр класса.
Panzerschrek[CN]
> Например, в крестах:
Кстати это пример в пользу Раста. В крестах нечитаемая баланда
А ещё в крестах можно так:
int main() { std::string d( ); }
Panzerschrek[CN]
> Например, в крестах:
> std::vector<size_t> a{1, 2, 3}, b(a), c(64, 32), d();
Согласен с Тарасом.
И у тебя, кстати, ошибка. d - это не стринга, а функция, принимающая ноль параметров и возвращающая стринг.
1 frag / 2 deaths
> А ещё в крестах можно так:
Не, без шуток, это работает прямо в списке деклараторов: https://godbolt.org/z/G6nbbxsPd
Имбирная Ведьмочка
> d - это не стринга, а функция, принимающая ноль параметров и возвращающая
> стринг.
Это же так круто для парсера когда минимум ключевых слов!!!
1 frag / 2 deaths
> Кстати это пример в пользу Раста.
Спорно. Подход Rust заставляет помнить имена кучи функций в классах, тогда как в крестах тупо зовёшь конструктор специальным синтаксисом.
1 frag / 2 deaths
> std::string d();
Имбирная Ведьмочка
> И у тебя, кстати, ошибка. d - это не стринга, а функция, принимающая ноль параметров и возвращающая стринг.
Это иная проблема - кривой крестосинтаксис. в Ü такой фигни нету.
Panzerschrek[CN]
> Спорно. Подход Rust заставляет помнить имена кучи функций в классах, тогда как
> в крестах тупо зовёшь конструктор специальным синтаксисом.
И что такое std::vector<int> a(3, 42)? Это 3 раза 42, или 42 раз 3?
Panzerschrek[CN]
> Подход Rust заставляет помнить имена кучи функций
Блокнотопроблемы, у нормальных людей IDE всё пишет сразу и ничего вспоминать не надо. B)
1 frag / 2 deaths
> И что такое std::vector<int> a(3, 42)? Это 3 раза 42, или 42 раз 3?
Ну справедливости ради, Vec<i32>::replicate(3, 42) тоже однозначностью не обременён.
1 frag / 2 deaths
> Это 3 раза 42, или 42 раз 3?
Или вообще, вектор из двух элементов - 3 и 42.
Отчасти проблема чинится строгой типизацией. Тогда нужно будет писать что-то вроде:
std::vector<int> a(size_t( 3), int( 42));
Имбирная Ведьмочка
> у нормальных людей IDE
Нема у Ü IDE.
Точнее, есть даже плагин под QtCreator, но он почти ничего не умеет и уже устарел.