Заставить заработать этот кусок потребовалось около получаса. Я все еще не понимаю разницы.
#[derive(Debug)]
struct Person {
name : String
}
fn main() {
let name = String::from("Alice");
let alice = Person { name };
let bob = Person { name: "Bob".to_string() };
for person in [alice, bob] {
println!("Hello, {:?}!", person);
}
let name = "Mary";
println!("Hello, {}!", name);
}
Для сравнения код на F#:
type Person = { name : string }
let name = "Alice"let alice = { name = name }
let bob = { name = "Bob" }
for e in [alice; bob ] do printfn "Hello, %A!" e
let name = "Mary"
printfn "hello, %s!" name
3 разных способа задать строковое значение. не многовато?
Впечатление от компилятора раста неплохие, в каждом месте подробное описание с подсказками, что можно сделать, не очень правда удачные.
например если в массиве поставить точку с запятой, то он предлагает боба пометить const,
помечаю , тогда он начинает верещать что bob надо заменить на bob : Person =. Зачем если тип справа определен?
Весело. Но если внимательно читать и постепенно исправлять то в конце концов собирается.
Смешанные чувства, то ли раст это одна большая бага, то ли фича
Здравствуйте, vaa, Вы писали:
vaa>fn main() { vaa> let name = String::from("Alice"); vaa> let alice = Person { name }; vaa> let bob = Person { name: "Bob".to_string() }; vaa> for person in [alice, bob] { vaa> println!("Hello, {:?}!", person); vaa> } vaa> let name = "Mary"; vaa> println!("Hello, {}!", name); vaa>} vaa>[/rust]
vaa>3 разных способа задать строковое значение. не многовато?
Первые 2 момента — String.
Третий — не String .
vaa>Смешанные чувства, то ли раст это одна большая бага, то ли фича
Да.
Здравствуйте, vaa, Вы писали:
vaa>3 разных способа задать строковое значение. не многовато?
Ну, понимаешь, строка, которую можно динамически изменять — это такая хитрая структурка данных, управляющая выделением памяти, буфер с символами, на который она ссылается, и всякое такое. А константная строка — это просто место в памяти, где лежат символы, и какой-то способ указать, где последовательность символов кончается ('\0', как в Си, или явный счетчик; не знаю уж, как в Русте).
Доступ к динамической строке чуть дороже. Руст считает своим долгом предоставить программисту возможность сэкономить пару-тройку тактов процессора там и сям, как и пару-тройку байтов. Поэтому да, константные строки и динамические строки — это разные зверушки.
Более высокоуровневый F# игнорирует мелкую экономию ради простоты. Поэтому да, в нем все проще.
Здравствуйте, Pzz, Вы писали:
Pzz>Более высокоуровневый F# игнорирует мелкую экономию ради простоты. Поэтому да, в нем все проще.
Ничего он по факту не игнорирует, потому что, помимо string, есть еще StringBuilder и Span<char>/ReadOnlySpan<char>. Другое дело что если тот же ReadOnlySpan<char> массово пролазит в прикладной код — вот это уже беда.
Здравствуйте, Pzz, Вы писали:
Pzz>Доступ к динамической строке чуть дороже. Руст считает своим долгом предоставить программисту возможность сэкономить пару-тройку тактов процессора там и сям, как и пару-тройку байтов. Поэтому да, константные строки и динамические строки — это разные зверушки.
Чем Rust лучше языка Ada?
Для работы с текстом в Аде существует несколько предопределённых типов: Character, Wide_Character, Wide_Wide_Character, String, Bounded_String, Unbounded_String
и т.д. Тема весьма обширна, а так как со строками мы только знакомимся, то на данном этапе я ограничусь использованием самых «ходовых» типов и операций. В следующем разделе для решения задач нам понадобятся типы:
Character
— для работы с простыми символами (ASCII, не Unicode) (в принципе, работа с Wide_Characters
ничем не отличается);
String
— для работы с простыми строками (фактически это массивы заданной длины, состоящие из символов типа Character
);
Unbounded_String
— для работы со строками неопределённой длины. Т.е. размер переменной, в которую будет считываться строка, меняет свой размер по мере необходимости.
А вообще чем дальше тем больше начинает казаться, что в современном мейнстриме недооценена Ada. Язык дает немало средств для защищенного программирования, при этом с нативной компиляцией, ООП, языковые средства мультизадачности и т.д. Язык не академический, имеет кучу компиляторов, применяется как в микроконтроллерах, так и в некоторых бизнес-системах (хотя и редко).
Здравствуйте, Michael7, Вы писали:
Pzz>>Доступ к динамической строке чуть дороже. Руст считает своим долгом предоставить программисту возможность сэкономить пару-тройку тактов процессора там и сям, как и пару-тройку байтов. Поэтому да, константные строки и динамические строки — это разные зверушки.
M>Чем Rust лучше языка Ada?
Ты б еще ASN.1 помянул
M>А вообще чем дальше тем больше начинает казаться, что в современном мейнстриме недооценена Ada. Язык дает немало средств для защищенного программирования, при этом с нативной компиляцией, ООП, языковые средства мультизадачности и т.д. Язык не академический, имеет кучу компиляторов, применяется как в микроконтроллерах, так и в некоторых бизнес-системах (хотя и редко).
Ада является местами отраслевым стандартом. В основном, вокруг военных, самолетных и космических направлений.
Здравствуйте, Michael7, Вы писали:
M>Чем Rust лучше языка Ada?
Фортран 4 все равно никто не превзойдет. Там строковых переменных не было вообще, зато строковых констант было 3 типа. Строковые переменные ввели в Фортране 77.
M>А вообще чем дальше тем больше начинает казаться, что в современном мейнстриме недооценена Ada.
К счастью, язык одобряемый Министерством Обороны, обладает достаточно интересными свойствами, которые делают его приемлемым — он невероятно сложен, включает в себя способы порчи операционной системы и перераспределения памяти, и Эдгар Дейкстра (Edsgar Dijkstra) не любит его.
Здравствуйте, vaa, Вы писали:
vaa>3 разных способа задать строковое значение. не многовато?
На самом деле больше:
let s = "aaa".to_string();
let s = String::from("aaa");
let s: String = "aaa".into();
let s: String = "aaa".chars().collect();
let s = String::from_utf8("aaa".as_bytes().to_vec()).unwrap();
let s = String::from_utf8(b"aaa".to_vec()).unwrap();
let s = String::from_utf16(&"aaa".encode_utf16().collect::<Vec<u16>>()).unwrap();
и можно продолжать и продолжать.
Но в любом языке программирования так,
можно написать бесконечное множество функций переводящих данные типа T1
в тип T2.
Здравствуйте, Pzz, Вы писали:
Pzz>Здравствуйте, vaa, Вы писали:
Pzz>Доступ к динамической строке чуть дороже. Руст считает своим долгом предоставить программисту возможность сэкономить пару-тройку тактов процессора там и сям, как и пару-тройку байтов. Поэтому да, константные строки и динамические строки — это разные зверушки.
Ну для порядка стоит сказать что типы разные, но оперировать они могут
буквально одними и теми же данными:
let s_const: &str = "aaa";
let s_heap: String = s_const.into();
let s_const2: &str = &s_heap;
То есть s_const2 и s_heap указывают на один и тот же участок памяти.
Отличие (с точки зрения языка) s_const и s_const2 только в том что время жизни у них разное,
для s_const2 компилятор проверит что она живет не дольше s_heap, а вот
время жизни s_const равно времени жизни всей программы.
Pzz>Более высокоуровневый F# игнорирует мелкую экономию ради простоты. Поэтому да, в нем все проще.
Да, F# другой строкоывый тип, другие над ним операции,
но с абстрактной точки зрения разница не очень большая,
что в Rust что в F# можно объявить типы T1 и T2, так чтобы T1 реализовывал
только часть методов реализованных для T2 и написать какой-нибудь метод для T1
который вернет T2. Не понятно что такого особенного в этом увидел ТС.
Здравствуйте, Zhendos, Вы писали:
Z>Да, F# другой строкоывый тип, другие над ним операции, Z>но с абстрактной точки зрения разница не очень большая, Z>что в Rust что в F# можно объявить типы T1 и T2, так чтобы T1 реализовывал Z>только часть методов реализованных для T2 и написать какой-нибудь метод для T1 Z>который вернет T2. Не понятно что такого особенного в этом увидел ТС.
Высокоуровневые ЯП обычно стремятся к максимальному уровню абстракции, пытаясь обобщить работу
с различными структурами данными. Рич Хикки замечательно продемонстрировал в кложе, что это возможно.
(defn f [x] x)
(map f [1 2 3]) // => (1 2 3)
(map f "hello") //=> (\h \e \l \l \o)
vaa>(defn f [x] x)
vaa>(map f [1 2 3]) // => (1 2 3)
vaa>(map f "hello") //=> (\h \e \l \l \o)
vaa>
vaa>Или раст не высокоуровневый ЯП?
Так вы же с этим и столкнулись и именно это вам не понравилось?
Все эти 10 способов перевести переменную типа "&str" в тип "String"
проистекают именно из желания писать абстракции.
"to_string" это из "trait ToString",
то есть чтобы писать такой "generic" код:
Метод "from" из "trait From", метод "into" из "trait Into",
метод "collect" из "trait Iterator" и т.д.
И эти "trait" реализованы не только для "&str", но и еще
для кучи типов (и их конечно можно реализовать для своего типа).
То есть именно желание абстрагироваться привело
к стольким способам конвертации из типа "&str" в "String".