Explorando los conceptos de cadenas en Rust

RustRustBeginner
Practicar Ahora

This tutorial is from open-source community. Access the source code

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este laboratorio, exploraremos el concepto de cadenas en Rust. Rust tiene dos tipos de cadenas: String y &str.

Una String es una cadena asignada en el montón y crecible que está garantizada para ser una secuencia UTF-8 válida. Por otro lado, &str es una porción que apunta a una secuencia UTF-8 válida y se puede utilizar para ver dentro de una String.

En Rust, los literales de cadena se pueden escribir de diferentes maneras, incluyendo el uso de escapes para representar caracteres especiales. Por ejemplo, \x3F representa el carácter de interrogación y \u{211D} representa un punto de código Unicode. También se pueden utilizar literales de cadena sin procesar si se desea escribir una cadena tal cual sin escapes.

Si es necesario trabajar con cadenas de bytes, Rust proporciona literales de cadena de bytes utilizando el prefijo b. Las cadenas de bytes pueden tener escapes de bytes, pero no escapes Unicode. Las cadenas de bytes sin procesar también se pueden utilizar de manera similar a los literales de cadena sin procesar.

Es importante tener en cuenta que str y String deben siempre ser secuencias UTF-8 válidas. Si es necesario trabajar con cadenas en diferentes codificaciones, se pueden utilizar cajas externas como encoding para realizar conversiones entre codificaciones de caracteres.

Nota: Si el laboratorio no especifica un nombre de archivo, puede utilizar cualquier nombre de archivo que desee. Por ejemplo, puede utilizar main.rs, compilar y ejecutarlo con rustc main.rs &&./main.

Cadenas

En Rust, hay dos tipos de cadenas: String y &str.

Una String se almacena como un vector de bytes (Vec<u8>), pero está garantizada para siempre ser una secuencia UTF-8 válida. String se asigna en el montón, es crecible y no está terminada en nulo.

&str es una porción (&[u8]) que siempre apunta a una secuencia UTF-8 válida y se puede utilizar para ver dentro de una String, al igual que &[T] es una vista dentro de Vec<T>.

fn main() {
    // (todas las anotaciones de tipo son superfluas)
    // Una referencia a una cadena asignada en memoria de solo lectura
    let pangram: &'static str = "the quick brown fox jumps over the lazy dog";
    println!("Pangram: {}", pangram);

    // Itera sobre las palabras en orden inverso, no se asigna una nueva cadena
    println!("Palabras en orden inverso");
    for word in pangram.split_whitespace().rev() {
        println!("> {}", word);
    }

    // Copia los caracteres en un vector, los ordena y elimina los duplicados
    let mut chars: Vec<char> = pangram.chars().collect();
    chars.sort();
    chars.dedup();

    // Crea una `String` vacía y crecible
    let mut string = String::new();
    for c in chars {
        // Inserta un carácter al final de la cadena
        string.push(c);
        // Inserta una cadena al final de la cadena
        string.push_str(", ");
    }

    // La cadena recortada es una porción de la cadena original, por lo tanto no se realiza
    // una nueva asignación
    let chars_to_trim: &[char] = &[' ', ','];
    let trimmed_str: &str = string.trim_matches(chars_to_trim);
    println!("Caracteres utilizados: {}", trimmed_str);

    // Asigna memoria en el montón para una cadena
    let alice = String::from("I like dogs");
    // Asigna nueva memoria y almacena la cadena modificada allí
    let bob: String = alice.replace("dog", "cat");

    println!("Alice dice: {}", alice);
    println!("Bob dice: {}", bob);
}

Se pueden encontrar más métodos de str/String en los módulos std::str y std::string

Literales y escapes

Hay múltiples maneras de escribir literales de cadena con caracteres especiales en ellos. Todos resultan en un &str similar, por lo que es mejor utilizar la forma que sea más conveniente de escribir. Del mismo modo, hay múltiples maneras de escribir literales de cadena de bytes, que todos resultan en &[u8; N].

Generalmente, los caracteres especiales se escapan con un carácter barra invertida: \. De esta manera, se puede agregar cualquier carácter a su cadena, incluso aquellos no imprimibles y aquellos que no sabe cómo escribir. Si desea una barra invertida literal, escápela con otra: \\

Los delimitadores de literales de cadena o carácter que aparecen dentro de un literal deben ser escapados: "\"", '\''.

fn main() {
    // Puede utilizar escapes para escribir bytes por sus valores hexadecimales...
    let byte_escape = "I'm writing \x52\x75\x73\x74!";
    println!("¿Qué estás haciendo\x3F (\\x3F significa?) {}", byte_escape);

    //...o puntos de código Unicode.
    let unicode_codepoint = "\u{211D}";
    let character_name = "\"DOUBLE-STRUCK CAPITAL R\"";

    println!("El carácter Unicode {} (U+211D) se llama {}",
                unicode_codepoint, character_name );


    let long_string = "String literals
                        can span multiple lines.
                        The linebreak and indentation here ->\
                        <- can be escaped too!";
    println!("{}", long_string);
}

A veces, simplemente hay demasiados caracteres que deben ser escapados o es simplemente mucho más conveniente escribir una cadena tal cual. Aquí es donde entran en juego los literales de cadena sin procesar.

fn main() {
    let raw_str = r"Escapes don't work here: \x3F \u{211D}";
    println!("{}", raw_str);

    // Si necesita comillas en una cadena sin procesar, agregue un par de #s
    let quotes = r#"And then I said: "There is no escape!""#;
    println!("{}", quotes);

    // Si necesita "## en su cadena, simplemente use más #s en el delimitador.
    // Puede usar hasta 65535 #s.
    let longer_delimiter = r###"A string with "## in it. And even "##!"###;
    println!("{}", longer_delimiter);
}

¿Quieres una cadena que no sea UTF-8? (Recuerde, str y String deben ser UTF-8 válidos). O quizás quieres una matriz de bytes que sea mayormente texto? ¡Las cadenas de bytes a la rescate!

use std::str;

fn main() {
    // Tenga en cuenta que esto no es realmente un `&str`
    let bytestring: &[u8; 21] = b"this is a byte string";

    // Las matrices de bytes no tienen el trato `Display`, por lo que imprimirlas está un poco limitado
    println!("Una cadena de bytes: {:?}", bytestring);

    // Las cadenas de bytes pueden tener escapes de bytes...
    let escaped = b"\x52\x75\x73\x74 as bytes";
    //...pero no escapes Unicode
    // let escaped = b"\u{211D} is not allowed";
    println!("Algunos bytes escapados: {:?}", escaped);


    // Las cadenas de bytes sin procesar funcionan igual que las cadenas sin procesar
    let raw_bytestring = br"\u{211D} is not escaped here";
    println!("{:?}", raw_bytestring);

    // Convertir una matriz de bytes a `str` puede fallar
    if let Ok(my_str) = str::from_utf8(raw_bytestring) {
        println!("Y lo mismo que texto: '{}'", my_str);
    }

    let _quotes = br#"You can also use "fancier" formatting, \
                    like with normal raw strings"#;

    // Las cadenas de bytes no tienen que ser UTF-8
    let shift_jis = b"\x82\xe6\x82\xa8\x82\xb1\x82\xbb"; // "ようこそ" en SHIFT-JIS

    // Pero entonces no siempre se pueden convertir a `str`
    match str::from_utf8(shift_jis) {
        Ok(my_str) => println!("Conversión exitosa: '{}'", my_str),
        Err(e) => println!("Conversión fallida: {:?}", e),
    };
}

Para conversiones entre codificaciones de caracteres, consulte la caja de codificación.

Una lista más detallada de las maneras de escribir literales de cadena y caracteres de escape se da en el capítulo 'Tokens' de la Referencia de Rust.

Resumen

¡Felicitaciones! Has completado el laboratorio de Cadenas. Puedes practicar más laboratorios en LabEx para mejorar tus habilidades.