¿Cómo concateno cadenas?

199

¿Cómo concateno las siguientes combinaciones de tipos:

  • str y str
  • String y str
  • String y String
jsalter
fuente
14
Tenga en cuenta que stry &strson diferentes tipos y durante el 99% del tiempo, solo debe preocuparse &str. Hay otras preguntas que detallan las diferencias entre ellos.
Shepmaster

Respuestas:

235

Cuando concatena cadenas, necesita asignar memoria para almacenar el resultado. Lo más fácil para empezar es Stringy &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);
}

Aquí, tenemos una cadena propia que podemos mutar. Esto es eficiente ya que potencialmente nos permite reutilizar la asignación de memoria. Hay un caso similar para Stringy String, como &String se puede desreferenciar como&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);
}

Después de esto, another_owned_stringno se ha tocado (nota sin mutcalificador). Hay otra variante que consume el Stringpero no requiere que sea mutable. Esta es una implementación del Addrasgo que toma a Stringcomo el lado izquierdo y a &strcomo el lado derecho:

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

Tenga en cuenta que owned_stringya no se puede acceder después de la llamada a +.

¿Qué pasaría si quisiéramos producir una nueva cadena, dejando ambas sin tocar? La forma más simple es usar format!:

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

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

Tenga en cuenta que ambas variables de entrada son inmutables, por lo que sabemos que no se tocan. Si quisiéramos hacer lo mismo para cualquier combinación de String, podemos usar el hecho de que Stringtambién se puede formatear:

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

Sin embargo, no tienes que usar format!. Puede clonar una cadena y agregar la otra cadena a la nueva cadena:

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

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

Nota : toda la especificación de tipo que hice es redundante: el compilador puede inferir todos los tipos en juego aquí. ¡Los agregué simplemente para que sean claros para las personas nuevas en Rust, ya que espero que esta pregunta sea popular entre ese grupo!

Shepmaster
fuente
2
¿Qué opinas sobre Add/ +símbolo? Podrías cubrirlo si quieres.
rubor
Tal vez sea bastante simple, pero comprenderlo requiere observar las posibles firmas de tipo para Agregar con cadena.
rubor
¡Gracias! ¿Puede profundizar un poco más en cómo & String se puede desreferenciar como a & str? ¿Qué parte de su implementación permite eso y / o dónde dice esto en el doco?
jsalter
1
@jsalter es un tema bastante separado, por lo que puede ser bueno como otra pregunta de alto nivel. He actualizado para vincular a los documentos apropiados (lo más cerca que puedo llegar, al menos ...)
Shepmaster
10
@ChrisMorgan Cabe señalar que la discrepancia .to_owned()y .to_string()se ha solucionado desde el comentario anterior gracias a la especialización implícita. Ambos ahora tienen el mismo rendimiento cuando se les llama a &str. Compromiso
chad
49

Para concatenar múltiples cadenas en una sola cadena, separadas por otro carácter, hay un par de formas.

Lo mejor que he visto es usar el joinmétodo en una matriz:

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

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

Dependiendo de su caso de uso, también puede preferir más control:

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

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

He visto algunas formas más manuales, algunas evitando una o dos asignaciones aquí y allá. Para propósitos de legibilidad, encuentro que los dos anteriores son suficientes.

Simon Whitehead
fuente
¿Dónde está joindocumentado? Parece estar a medio camino entre una matriz y una cadena. Busqué en la documentación de la matriz y rápidamente me confundí.
Duane J
3
@DuaneJ joinse une realmente a la SliceContactExtcaracterística . El rasgo está marcado como inestable, pero sus métodos son estables y están incluidos en el Preludio, por lo que pueden usarse en todas partes de forma predeterminada. El equipo parece ser muy consciente de que este rasgo no necesita existir e imagino que las cosas cambiarán en el futuro con él.
Simon Whitehead
9

Creo que ese concatmétodo y +debería mencionarse aquí también:

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

y también hay concat!macro pero solo para literales:

let s = concat!("test", 10, 'b', true);
assert_eq!(s, "test10btrue");
suside
fuente
+ya se menciona en una respuesta existente . ( Esta es una implementación de la Addcaracterística que toma Stringcomo el lado de la mano izquierda y una &strcomo el lado derecho: )
Shepmaster
Es cierto que la respuesta existente es tan amplia que no me di cuenta.
Suside
6

Formas simples de concatenar cadenas en RUST

Hay varios métodos disponibles en RUST para concatenar cadenas

Primer método (usando concat!()):

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

La salida del código anterior es:

ab


Segundo método (usando push_str()y +operador):

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 salida del código anterior es:

ab

a B C


Tercer método ( Using format!()):

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

La salida del código anterior es:

ab

échale un vistazo y experimenta con Rust Play Ground

ASHWIN RAJEEV
fuente
Esta respuesta no agrega nada nuevo a las respuestas existentes.
Shepmaster