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


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.