Jak łączyć łańcuchy?


199

Jak połączyć następujące kombinacje typów:

  • str i str
  • String i str
  • String i String

14
Należy pamiętać, że stri &strróżne rodzaje i do 99% czasu, tylko powinien dbać o &str. Są też inne pytania wyszczególniające różnice między nimi.
Shepmaster

Odpowiedzi:


235

Podczas łączenia łańcuchów należy przydzielić pamięć, aby zapisać wynik. Najłatwiej jest zacząć Stringa &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);
}

Tutaj mamy własny ciąg, który możemy mutować. Jest to wydajne, ponieważ potencjalnie pozwala nam ponownie wykorzystać przydział pamięci. Istnieje podobny przypadek Stringi String, jak &String można wyrejestrować jako&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);
}

Po tym another_owned_stringjest nietknięty (nie ma mutkwalifikatora). Jest jeszcze jeden wariant, który zużywaString ale nie wymaga to być zmienny. Jest to implementacja Addcechy, która przyjmuje Stringjako lewą stronę i &strjako prawą stronę:

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);
}

Pamiętaj, że owned_stringnie jest już dostępny po połączeniu z +.

Co jeśli chcielibyśmy wyprodukować nowy ciąg, pozostawiając oba nietknięte? Najprostszym sposobem jest użycie format!:

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

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

Zauważ, że obie zmienne wejściowe są niezmienne, więc wiemy, że nie są dotykane. Jeśli chcielibyśmy zrobić to samo dla dowolnej kombinacji String, możemy skorzystać z faktu, że Stringmożna również sformatować:

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);
}

Nie musisz jednak używać format!. Możesz sklonować jeden ciąg i dołączyć drugi do nowego:

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

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

Uwaga - cała specyfikacja typu, którą zrobiłem, jest zbędna - kompilator może wnioskować o wszystkich typach tutaj odtwarzanych. Dodałem je po prostu, aby były jasne dla osób początkujących w Rust, ponieważ spodziewam się, że to pytanie będzie popularne wśród tej grupy!


2
Co sądzisz o Add/ +symbol? Możesz to pokryć, jeśli chcesz.
bezmyślnie

Może to dość proste, ale zrozumienie tego wymaga spojrzenia na możliwe typy podpisów dla Add with String.
bezmyślnie

Dzięki! Czy jesteś w stanie wniknąć nieco głębiej w to, w jaki sposób & String można wyrejestrować jako a & str? Która część jego realizacji pozwala na to i / lub gdzie mówi to w doco?
jsalter

1
@jsalter to dość osobny temat, więc może być dobrym pytaniem na najwyższym poziomie. Zaktualizowałem link do odpowiednich dokumentów (przynajmniej tak blisko, jak to możliwe, przynajmniej ...)
Shepmaster

10
@ChrisMorgan Należy zauważyć, że rozbieżność .to_owned()i .to_string()została naprawiona od powyższego komentarza dzięki specjalizacji impl. Oba mają teraz taką samą wydajność, gdy są wywoływane &str. Odpowiednie zatwierdzanie: github.com/rust-lang/rust/pull/32586/files
czad

49

Aby połączyć wiele ciągów w jeden ciąg oddzielony innym znakiem, istnieje kilka sposobów.

Najmilsze, jakie widziałem, to użycie joinmetody na tablicy:

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

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

W zależności od przypadku użycia możesz również preferować większą kontrolę:

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

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

Widziałem kilka ręcznych sposobów, niektóre unikały jednego lub dwóch przydziałów tu i tam. Dla celów czytelności powyższe dwa są wystarczające.


Gdzie jest joinudokumentowane? Wydaje się, że znajduje się w połowie drogi między tablicą a łańcuchem. Przeszukałem dokumentację tablicy i szybko się pomyliłem.
Duane J

3
@DuaneJ joinjest właściwie przymocowany do tej SliceContactExtcechy . Cecha jest oznaczona jako niestabilna, ale jej metody są stabilne i są uwzględnione w Preludium, dzięki czemu można je stosować wszędzie domyślnie. Zespół wydaje się być świadomy, że ta cecha nie musi istnieć i myślę, że wraz z nią wszystko się zmieni.
Simon Whitehead,

9

Myślę, że tę concatmetodę +należy również wymienić:

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

i jest też concat!makro, ale tylko dla literałów:

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

+jest już wspomniany w istniejącej odpowiedzi . ( Jest to realizacja Addcecha, która trwa Stringjako lewej strony a &strjak po prawej stronie: )
Shepmaster

To prawda, że istniejąca odpowiedź jest tak szeroka, że ​​jej nie zauważyłem.
suside

6

Proste sposoby łączenia łańcuchów w RUST

W RUST dostępne są różne metody łączenia łańcuchów

Pierwsza metoda (za pomocą concat!()):

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

Dane wyjściowe powyższego kodu to:

ab


Druga metoda (użycie push_str()i +operator):

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);
}

Dane wyjściowe powyższego kodu to:

ab

ABC


Trzecia metoda ( Using format!()):

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

Dane wyjściowe powyższego kodu to:

ab

sprawdź to i eksperymentuj z placem zabaw Rust


Ta odpowiedź nie dodaje nic nowego do istniejących odpowiedzi.
Shepmaster
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.