Wie verkette ich Zeichenfolgen?

192

Wie verkette ich die folgenden Typenkombinationen:

  • str und str
  • String und str
  • String und String
jsalter
quelle
13
Beachten Sie, dass strund &strsind verschiedene Typen und für 99% der Zeit, sollten Sie nur kümmern uns um &str. Es gibt andere Fragen, die die Unterschiede zwischen ihnen detailliert beschreiben.
Shepmaster

Antworten:

228

Wenn Sie Zeichenfolgen verketten, müssen Sie Speicher zuweisen, um das Ergebnis zu speichern. Am einfachsten ist Stringund &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);
}

Hier haben wir eine eigene Zeichenfolge, die wir mutieren können. Dies ist effizient, da wir möglicherweise die Speicherzuordnung wiederverwenden können. Es gibt einen ähnlichen Fall für Stringund String, wie &String dereferenziert werden kann als&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);
}

Danach another_owned_stringbleibt unberührt (kein mutQualifier beachten ). Es gibt eine weitere Variante , die verbraucht die Stringaber nicht erfordert es wandelbar zu sein. Dies ist eine Implementierung des AddMerkmals , das a Stringals linke Seite und a &strals rechte Seite nimmt:

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

Beachten Sie, dass owned_stringnach dem Anruf an nicht mehr darauf zugegriffen werden kann +.

Was wäre, wenn wir eine neue Saite produzieren wollten, die beide unberührt ließ? Der einfachste Weg ist zu verwenden format!:

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

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

Beachten Sie, dass beide Eingabevariablen unveränderlich sind, sodass wir wissen, dass sie nicht berührt werden. Wenn wir das Gleiche für eine beliebige Kombination von tun wolltenString , können wir die Tatsache nutzen, dass Stringauch formatiert werden kann:

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

Sie müssen nicht haben zu verwenden ,format! , though. Sie können eine Zeichenfolge klonen und die andere Zeichenfolge an die neue Zeichenfolge anhängen:

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

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

Hinweis - Alle von mir erstellten Typspezifikationen sind redundant. Der Compiler kann auf alle hier verwendeten Typen schließen. Ich habe sie einfach hinzugefügt, um Leuten, die neu bei Rust sind, klar zu sein, da ich erwarte, dass diese Frage bei dieser Gruppe beliebt ist!

Shepmaster
quelle
2
Was denkst du über Add/ +symbol? Sie könnten es abdecken, wenn Sie wollen.
Bluss
Vielleicht ist das einfach genug, aber um es zu verstehen, müssen die möglichen Typensignaturen für Add with String geprüft werden.
Bluss
Vielen Dank! Können Sie etwas genauer untersuchen, wie & String als & str dereferenziert werden kann? Welcher Teil seiner Implementierung erlaubt dies und / oder wo steht dies im Dokument?
jsalter
1
@jsalter, das ist ein ziemlich separates Thema, daher kann es als weitere Frage der obersten Ebene gut sein. Ich habe aktualisiert, um auf die entsprechenden Dokumente zu verlinken (so nah wie möglich, zumindest ...)
Shepmaster
10
@ChrisMorgan Es sollte beachtet werden, dass die Diskrepanz .to_owned()und .to_string()seit dem obigen Kommentar dank impl Spezialisierung behoben wurde. Beide haben jetzt die gleiche Leistung, wenn sie auf a gerufen werden &str. Relevantes Commit: github.com/rust-lang/rust/pull/32586/files
chad
48

Es gibt verschiedene Möglichkeiten, mehrere Zeichenfolgen zu einer einzelnen Zeichenfolge zu verketten, die durch ein anderes Zeichen getrennt sind.

Das Schönste, was ich gesehen habe, ist die Verwendung der joinMethode für ein Array:

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

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

Abhängig von Ihrem Anwendungsfall bevorzugen Sie möglicherweise auch mehr Kontrolle:

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

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

Es gibt einige weitere manuelle Methoden, die ich gesehen habe, einige, die hier und da ein oder zwei Zuordnungen vermeiden. Aus Gründen der Lesbarkeit halte ich die beiden oben genannten für ausreichend.

Simon Whitehead
quelle
Wo ist joindokumentiert? Es scheint auf halbem Weg zwischen einem Array und einem String zu liegen. Ich durchsuchte die Array- Dokumentation und war schnell verwirrt.
Duane J
3
@ DuaneJ joinist tatsächlich mit dem SliceContactExtMerkmal verbunden . Das Merkmal ist als instabil markiert, aber seine Methoden sind stabil und im Prelude enthalten, sodass sie standardmäßig überall verwendet werden können. Das Team scheint sich bewusst zu sein, dass dieses Merkmal nicht existieren muss, und ich kann mir vorstellen, dass sich die Dinge in Zukunft damit ändern werden.
Simon Whitehead
9

Ich denke diese concatMethode und +sollte auch hier erwähnt werden:

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

und es gibt auch concat!Makro, aber nur für Literale:

let s = concat!("test", 10, 'b', true);
assert_eq!(s, "test10btrue");
suside
quelle
+wird bereits in einer bestehenden Antwort erwähnt . ( Dies ist eine Implementierung des AddMerkmals , dass ein nimmt , Stringwie auf der linken Seite und eine &strals die rechte Seite: )
Shepmaster
Die vorhandene Antwort ist zwar so weit gefasst, dass ich sie jedoch nicht bemerkt habe.
Suside
5

Einfache Möglichkeiten, Zeichenfolgen in RUST zu verketten

In RUST stehen verschiedene Methoden zum Verketten von Zeichenfolgen zur Verfügung

Erste Methode (mit concat!()):

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

Die Ausgabe des obigen Codes lautet:

ab


Zweite Methode (mit push_str()und +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);
}

Die Ausgabe des obigen Codes lautet:

ab

ABC


Dritte Methode ( Using format!()):

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

Die Ausgabe des obigen Codes lautet:

ab

Probieren Sie es aus und experimentieren Sie mit Rust Spielplatz

ASHWIN RAJEEV
quelle
Diese Antwort fügt den vorhandenen Antworten nichts Neues hinzu.
Shepmaster