Як з'єднати рядки?


199

Як об'єднати такі комбінації типів:

  • str і str
  • String і str
  • String і String

14
Зверніть увагу , що strі &strє різними типами і 99% часу, ви тільки повинні піклуватися про &str. Є й інші питання, що деталізують відмінності між ними.
Шепмайстер

Відповіді:


235

Коли ви об'єднуєте рядки, вам потрібно виділити пам'ять для зберігання результату. Простіше за все почати з Stringі &str:

fn main() {
    let mut owned_string: String = "hello ".to_owned();
    let borrowed_string: &str = "world";

    owned_string.push_str(borrowed_string);
    println!("{}", owned_string);
}

Тут у нас є власний рядок, який ми можемо мутувати. Це ефективно, оскільки потенційно дозволяє повторно використовувати розподіл пам'яті. Існує аналогічний випадок Stringі String, як &String це можна відкинути&str .

fn main() {
    let mut owned_string: String = "hello ".to_owned();
    let another_owned_string: String = "world".to_owned();

    owned_string.push_str(&another_owned_string);
    println!("{}", owned_string);
}

Після цього another_owned_stringвін недоторканий (відзначте, що немає mutкваліфікатора). Там ще один варіант , який споживаєString , але не вимагає від нього бути змінними. Це реалізація Addознаки, яка приймає Stringяк ліву, &strтак і праву:

fn main() {
    let owned_string: String = "hello ".to_owned();
    let borrowed_string: &str = "world";

    let new_owned_string = owned_string + borrowed_string;
    println!("{}", new_owned_string);
}

Зверніть увагу, що owned_stringпісля дзвінка на доступ більше не можна отримати доступ +.

Що робити, якщо ми хотіли створити нову струну, залишивши обох недоторканими? Найпростіший спосіб - це використовувати format!:

fn main() {
    let borrowed_string: &str = "hello ";
    let another_borrowed_string: &str = "world";

    let together = format!("{}{}", borrowed_string, another_borrowed_string);
    println!("{}", together);
}

Зауважте, що обидві вхідні змінні незмінні, тому ми знаємо, що вони не торкаються. Якщо ми хотіли зробити те ж саме для будь-якої комбінації String, ми можемо використати той факт, який Stringтакож може бути відформатований:

fn main() {
    let owned_string: String = "hello ".to_owned();
    let another_owned_string: String = "world".to_owned();

    let together = format!("{}{}", owned_string, another_owned_string);
    println!("{}", together);
}

Не потрібно користуватися, format!хоча. Ви можете клонувати один рядок і додати інший рядок до нового рядка:

fn main() {
    let owned_string: String = "hello ".to_owned();
    let borrowed_string: &str = "world";

    let together = owned_string.clone() + borrowed_string;
    println!("{}", together);
}

Примітка - вся специфікація типу, яку я зробив, є зайвою - компілятор може зробити висновок про всі типи, які тут відтворюються. Я додав їх просто для того, щоб зрозуміти людям, які не знайомі з Рустом, оскільки очікую, що це питання буде популярним у цій групі!


2
Що ти думаєш про Add/ +символ? Ви можете прикрити це, якщо хочете.
червоніє

Можливо, це досить просто, але для його розуміння потрібно переглянути можливі підписи типів для Add with String.
червоніє

Дякую! Чи можете ви трохи більше заглибитись у те, як & String можна знецінити як & str? Яка частина його реалізації дозволяє це та / або де це говориться в doco?
jsalter

1
@jsalter - це досить окрема тема, тому це може бути добре як ще одне питання вищого рівня. Я оновив посилання на відповідні документи (якнайближче я можу отримати, принаймні ...)
Шепмайстер,

10
@ChrisMorgan Слід зазначити, що розбіжність .to_owned()і .to_string()була виправлена ​​з моменту вищезазначеного коментаря завдяки спеціалізації імпульсу. Зараз вони обоє мають однакову ефективність, коли їх викликають &str. Відповідна комісія
чад

49

Для об'єднання декількох рядків в один рядок, розділених іншим символом, існує кілька способів.

Найприємніше, що я бачив - це використання joinметоду в масиві:

fn main() {
    let a = "Hello";
    let b = "world";
    let result = [a, b].join("\n");

    print!("{}", result);
}

Залежно від випадку використання ви також можете віддати перевагу більшому контролю:

fn main() {
    let a = "Hello";
    let b = "world";
    let result = format!("{}\n{}", a, b);

    print!("{}", result);
}

Я бачив ще кілька ручних способів, які уникають одного або двох виділень тут і там. Для читання я вважаю, що зазначені вище два є достатніми.


Де це joinзадокументовано? Начебто сидить на півдорозі між масивом та рядком. Я шукав документацію масиву і швидко плутався.
Дуейн J

3
@DuaneJ joinфактично приєднаний до до SliceContactExtбіса . Ця ознака позначена нестабільною, але її методи стабільні та включені до прелюдії, тому вони можуть бути використані скрізь за замовчуванням. Команда, здається, добре усвідомлює, що ця риса не повинна існувати, і я думаю, що з нею все зміниться в майбутньому.
Саймон Уайтхед

9

Я думаю, що цей concatметод і тут +слід згадати:

assert_eq!(
  ("My".to_owned() + " " + "string"),
  ["My", " ", "string"].concat()
);

і є також concat!макрос, але тільки для літералів:

let s = concat!("test", 10, 'b', true);
assert_eq!(s, "test10btrue");

+вже згадується в існуючій відповіді . ( Це реалізація Addознаки , який приймає в Stringякості сторони лівого боку , і &strяк з правого боку: )
Shepmaster

Щоправда, існуюча відповідь настільки широка, що я не помічав.
самогубство

6

Прості способи об'єднання рядків у RUST

У RUST доступні різні методи об'єднання рядків

Перший метод (використання concat!()):

fn main() {
    println!("{}", concat!("a", "b"))
}

Вихід з вищевказаного коду:

аб


Другий метод (з використанням push_str()та +оператора):

fn main() {
    let mut _a = "a".to_string();
    let _b = "b".to_string();
    let _c = "c".to_string();

    _a.push_str(&_b);
    
    println!("{}", _a);
 
    println!("{}", _a + &_b);
}

Вихід з вищевказаного коду:

аб

абс


Третій метод ( Using format!()):

fn main() {
    let mut _a = "a".to_string();
    let _b = "b".to_string();
    let _c = format!("{}{}", _a, _b);
    
    println!("{}", _c);
}

Вихід з вищевказаного коду:

аб

перевірити це та поекспериментувати з ігровим майданчиком Rust


Ця відповідь не додає нічого нового до існуючих відповідей.
Шепмейстер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.