Чому іржа Stringі str? Які відмінності між Stringі str? Коли використовується один, Stringа не strнавпаки? Хтось із них стає застарілим?
Чому іржа Stringі str? Які відмінності між Stringі str? Коли використовується один, Stringа не strнавпаки? Хтось із них стає застарілим?
Відповіді:
String- це тип динамічного рядка купи, наприклад Vec: використовуйте його, коли потрібно володіти або змінювати ваші рядкові дані.
strє незмінною 1 послідовністю байт UTF-8 динамічної довжини десь у пам'яті. Оскільки розмір невідомий, обробляти його можна лише за вказівником. Це означає, що strнайчастіше 2 виглядає як &str: посилання на деякі дані UTF-8, зазвичай їх називають "рядковим фрагментом" або просто "фрагментом". Фрагмент - це лише перегляд деяких даних, і ці дані можуть бути де завгодно, наприклад
"foo"- це a &'static str. Дані жорстко кодуються у виконуваний файл і завантажуються в пам'ять під час роботи програми.String : Stringразименовивает на &strпогляд з Stringданих «s.На стеку : наприклад, наступне створює байтовий масив, виділений стеком, а потім отримує представлення цих даних як&str :
use std::str;
let x: &[u8] = &[b'a', b'b', b'c'];
let stack_str: &str = str::from_utf8(x).unwrap();
Підсумовуючи це, використовуйте, Stringякщо вам потрібні дані про рядки, що належать (наприклад, передавання рядків до інших потоків або побудова їх під час виконання) та використовувати, &strякщо вам потрібен лише перегляд рядка.
Це ідентично співвідношенню між вектором Vec<T>і фрагментом &[T]і аналогічно співвідношенню між побічною величиною Tта посиланням &Tдля загальних типів.
1 А str- фіксованої довжини; ви не можете писати байтів поза межами кінця або залишати недійсні байти. Оскільки UTF-8 є кодуванням змінної ширини, це ефективно примушує всі strs бути непорушними у багатьох випадках. Взагалі мутація вимагає записати більше або менше байтів, ніж раніше (наприклад, заміна a(1 байт) на ä(2+ байтів) вимагала б більше місця в str). Існують конкретні методи, які можуть змінювати &strмісце, в основному ті, що працюють лише з символами ASCII make_ascii_uppercase.
2 Типи з динамічним розміром дозволяють на зразок Rc<str>послідовності посилань рахувати UTF-8 байт з Rust 1.2. Іржа 1,21 дозволяє легко створювати ці типи.
[u8; N].
Rc<str>і Arc<str>тепер можна використовувати з допомогою стандартної бібліотеки.
У мене є C ++, і мені було дуже корисно подумати Stringі про &strC ++:
Stringяк ніби std::string; вона володіє пам'яттю і виконує брудну роботу з управління пам'яттю.&strяк ніби char*(але трохи складніша); це вказує нам на початок фрагменту так само, як ви можете отримати вказівник на вміст std::string.Чи хтось із них зникне? Я так не думаю. Вони виконують дві цілі:
Stringзберігає буфер і дуже практичний у використанні. &strлегкий і його слід використовувати, щоб "заглянути" в струни. Ви можете шукати, розділяти, аналізувати та навіть замінювати шматки, не потребуючи виділення нової пам’яті.
&strможе заглянути всередину а, Stringяк це може вказувати на деякий буквальний рядок. Наступний код повинен скопіювати буквальний рядок в Stringкеровану пам'ять:
let a: String = "hello rust".into();
Наступний код дозволяє використовувати літерал без копії (хоча читати)
let a: &str = "hello rust";
str, використовується лише як &strфрагмент рядка, посилання на байтовий масив UTF-8.
String- це те, що раніше було ~str, байтовим масивом UTF-8, що займається можливістю використання .
~strтеперBox<str>
~strбуло вирощувати, а Box<str>не вирощувати. (Це ~strі ~[T]було магічно вирощуваним, на відміну від будь-якого іншого ~-об'єкта, саме тому Stringі Vec<T>було запроваджено, так що всі правила були чіткими та послідовними.)
Вони насправді зовсім інші. По-перше, a str- це не що інше, як річ на рівні типу; про це можна міркувати лише на рівні типу, оскільки це так званий тип динамічного розміру (DST). Розмір, який strзаймає, не може бути відомий під час компіляції і залежить від інформації часу виконання - він не може зберігатися в змінній, оскільки компілятору необхідно знати під час компіляції, який розмір кожної змінної. strКонцептуально A - це лише ряд u8байтів із гарантією того, що він утворює дійсний UTF-8. Наскільки великий ряд? Ніхто не знає, поки час його виконання не може бути збережений у змінній.
Цікаво те, що &strі будь-який інший покажчик на strLike Box<str> робить EXIST під час виконання. Це так званий «жировий покажчик»; це вказівник із додатковою інформацією (в даному випадку розміром речі, на яку він вказує), тож він удвічі більший. Насправді, a &strдосить близький до String(але не до a &String). А &str- це два слова; один вказівник на перший байт a strі інший номер, який описує, скільки байтів strдорівнює.
Всупереч сказаному, а strне потрібно бути незмінним. Якщо ви можете отримати &mut strексклюзивний покажчик на str, ви можете вимкнути його, і всі безпечні функції, які його мутують, гарантують, що обмеження UTF-8 підтримується, тому що якщо це порушено, ми маємо невизначене поведінку, оскільки бібліотека передбачає це обмеження. правда і не перевіряє на це.
Отже, що таке String? Це три слова; два - це те саме, що і для, &strале це додає третє слово - це ємність strбуфера на купі, завжди на купі (a strне обов'язково на купі), якою вона управляє, перш ніж її заповнити і доведеться перерозподілити. в Stringосновному володіє а, strяк кажуть; він контролює його і може змінити його розмір і перерозподілити його, коли вважає за потрібне. Тож а String, як сказано, ближче &strдо а str.
Інша справа - це Box<str>; цьому також належить a strі його представлення часу виконання таке ж, як, &strале воно також володіє на strвідміну від нього, &strале воно не може змінити його розмір, оскільки він не знає його ємності, а в основному a Box<str>може розглядатися як фіксована довжина, Stringяку неможливо змінити (ви можете завжди конвертуйте його у формат, Stringякщо ви хочете змінити його розмір).
Дуже схоже співвідношення існує між [T]і за Vec<T>винятком того, що немає UTF-8 , обмеження і він може містити будь-який тип, розмір якого не є динамічним.
Використання strна рівні типу здебільшого для створення загальних абстракцій &str; він існує на рівні типу, щоб можна було зручно писати риси. Теоретично, strяк річ типу, не потрібно було існувати і тільки, &strале це означало б писати багато зайвого коду, який тепер може бути загальним.
&strдуже корисно мати можливість мати декілька різних підрядків a Stringбез копіювання; як сказав String володієstr на купі вона управляє , і якщо ви можете створити тільки подстроку Stringз новим Stringвін повинен копіюватися , тому що все в іржі може мати тільки один єдиний власник , щоб мати справу з безпекою пам'яті. Так, наприклад, ви можете нарізати рядок:
let string: String = "a string".to_string();
let substring1: &str = &string[1..3];
let substring2: &str = &string[2..4];
У нас є дві різні підрядки strз одного рядка. stringце той, хто володіє фактичним повним strбуфером на купі, а &strпідрядки - лише жирні вказівники на цей буфер на купі.
std::Stringпросто вектор u8. Ви можете знайти його визначення у вихідному коді . Це купі, виділені та вирощувані.
#[derive(PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct String {
vec: Vec<u8>,
}
strце примітивний тип, який також називають струнним фрагментом . Струнковий фрагмент має фіксований розмір. Буквальний рядок типу let test = "hello world"має &'static strтип. testє посиланням на цей статично виділений рядок.
&strне можуть бути змінені, наприклад,
let mut word = "hello world";
word[0] = 's';
word.push('\n');
strмає змінний фрагмент &mut str, наприклад:
pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)
let mut s = "Per Martin-Löf".to_string();
{
let (first, last) = s.split_at_mut(3);
first.make_ascii_uppercase();
assert_eq!("PER", first);
assert_eq!(" Martin-Löf", last);
}
assert_eq!("PER Martin-Löf", s);
Але невелика зміна UTF-8 може змінити довжину байтів, і фрагмент не може перерозподілити його референта.
Простими словами, Stringтип даних зберігається в купі (точно так само Vec), і ви маєте доступ до цього місця.
&str- це тип зрізу. Це означає, що це лише посилання на вже присутнє Stringдесь у купі.
&strне виконує жодного розподілу під час виконання. Отже, з міркувань пам’яті ви можете використовувати &strпонад String. Але майте на увазі, що при використанні &strвам, можливо, доведеться мати справу з явними термінами життя.
strце viewз вже присутній Stringв купі.
Для людей з C # та Java:
String===StringBuilder &str === (незмінний) рядокМені подобається думати про &strвид як про рядок, як про інтерновану рядок у Java / C #, де ви не можете його змінити, лише створіть нову.
Ось швидке та просте пояснення.
String- Зростаюча, власна структура даних, що виділяється нагромадженням. Його можна примусити до а &str.
str- це (зараз, як Руст розвивається) змінний рядок фіксованої довжини, що живе на купі або у двійковій. Ви можете взаємодіяти з strтипом, запозиченим, лише через вигляд фрагмента рядка, наприклад &str.
Принципи використання:
Віддайте перевагу, Stringякщо ви хочете володіти або мутувати рядок - наприклад, передача рядка в інший потік тощо.
Віддайте перевагу, &strякщо ви хочете мати рядок лише для читання.
&strскладається з двох компонентів: покажчик на деякі байти і довжину.»