Comment concaténer des chaînes?

199

Comment concaténer les combinaisons de types suivantes:

  • str et str
  • String et str
  • String et String
jsalter
la source
14
Notez que stret &strsont de types différents et pour 99% du temps, vous ne devriez vous en soucier que &str. Il y a d'autres questions détaillant les différences entre elles.
Shepmaster

Réponses:

235

Lorsque vous concaténez des chaînes, vous devez allouer de la mémoire pour stocker le résultat. Le plus simple pour commencer est Stringet &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);
}

Ici, nous avons une chaîne possédée que nous pouvons muter. Ceci est efficace car cela nous permet potentiellement de réutiliser l'allocation de mémoire. Il existe un cas similaire pour Stringet String, comme cela &String peut être déréférencé comme&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);
}

Après cela, another_owned_stringn'est pas touché (notez pas de mutqualificatif). Il existe une autre variante qui consomme le Stringmais ne nécessite pas qu'il soit modifiable. Il s'agit d'une implémentation du Addtrait qui prend a Stringcomme côté gauche et a &strcomme côté droit:

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

Notez que ce owned_stringn'est plus accessible après l'appel à +.

Et si nous voulions produire une nouvelle chaîne en laissant les deux intactes? Le moyen le plus simple est d'utiliser format!:

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

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

Notez que les deux variables d'entrée sont immuables, nous savons donc qu'elles ne sont pas touchées. Si nous voulions faire la même chose pour n'importe quelle combinaison de String, nous pouvons utiliser le fait qui Stringpeut également être formaté:

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

Vous n'êtes pas obligé de l'utiliser format!. Vous pouvez cloner une chaîne et ajouter l'autre chaîne à la nouvelle chaîne:

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

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

Remarque - toute la spécification de type que j'ai faite est redondante - le compilateur peut déduire tous les types en jeu ici. Je les ai ajoutés simplement pour être clair pour les nouveaux utilisateurs de Rust, car je m'attends à ce que cette question soit populaire auprès de ce groupe!

Shepmaster
la source
2
Que pensez-vous de Add/ +symbol? Vous pouvez le couvrir si vous le souhaitez.
bluss
C'est peut-être assez simple, mais pour comprendre cela, il faut examiner les signatures de type possibles pour Add with String.
bluss
Merci! Êtes-vous en mesure d'approfondir un peu plus la façon dont & String peut être déréférencé en tant que & str? Quelle partie de son implémentation permet cela et / ou où est-il dit cela dans le doco?
jsalter
1
@jsalter est un sujet assez distinct, donc cela peut être une autre question de haut niveau. J'ai mis à jour pour
créer un
10
@ChrisMorgan Il convient de noter que l'écart .to_owned()et .to_string()a été corrigé depuis le commentaire ci-dessus grâce à la spécialisation impl. Ils ont tous deux maintenant les mêmes performances lorsqu'ils sont appelés sur un &str. Commit pertinent: github.com/rust-lang/rust/pull/32586/files
tchad
49

Pour concaténer plusieurs chaînes en une seule chaîne, séparées par un autre caractère, il existe plusieurs méthodes.

Le plus beau que j'ai vu utilise la joinméthode sur un tableau:

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

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

En fonction de votre cas d'utilisation, vous pouvez également préférer plus de contrôle:

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

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

J'ai vu d'autres méthodes manuelles, certaines évitant une ou deux allocations ici et là. Pour des raisons de lisibilité, je trouve les deux ci-dessus suffisants.

Simon Whitehead
la source
Où est joindocumenté? Il semble se situer à mi-chemin entre un tableau et une chaîne. J'ai cherché dans la documentation du tableau et j'ai été rapidement confus.
Duane J
3
@DuaneJ joinest réellement attaché à la SliceContactExttrait . Le trait est marqué comme instable mais ses méthodes sont stables et sont incluses dans le Prelude donc elles sont utilisables partout par défaut. L'équipe semble bien consciente que ce trait n'a pas besoin d'exister et j'imagine que les choses vont changer à l'avenir avec lui.
Simon Whitehead
9

Je pense que cette concatméthode et +devrait être mentionnée ici aussi:

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

et il y a aussi concat!macro mais uniquement pour les littéraux:

let s = concat!("test", 10, 'b', true);
assert_eq!(s, "test10btrue");
suside
la source
+est déjà mentionné dans une réponse existante . ( Ceci est une mise en œuvre du Addtrait qui prend Stringcomme côté gauche et &strque la droite: )
Shepmaster
Certes, la réponse existante est si large que je n'ai pas remarqué cependant.
suside le
6

Méthodes simples pour concaténer des chaînes dans RUST

Il existe différentes méthodes disponibles dans RUST pour concaténer des chaînes

Première méthode (en utilisant concat!()):

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

La sortie du code ci-dessus est:

un B


Deuxième méthode (en utilisant push_str()et +opérateur):

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

La sortie du code ci-dessus est:

un B

abc


Troisième méthode ( Using format!()):

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

La sortie du code ci-dessus est:

un B

Découvrez-le et expérimentez avec le terrain de jeu Rust

ASHWIN RAJEEV
la source
Cette réponse n'ajoute rien de nouveau aux réponses existantes.
Shepmaster le