[Aprender Rust juntos | Patrones de diseño] Gramática idiomática: uso de tipos prestados como parámetros, formateo y concatenación de cadenas y constructores

Sugerencia: después de escribir el artículo, la tabla de contenido se puede generar automáticamente. Cómo generarla puede consultar el documento de ayuda a la derecha


prefacio

Rust no es un lenguaje de programación orientado a objetos tradicional, y todas sus características lo hacen único. Por lo tanto, es necesario aprender patrones de diseño específicos de Rust. Esta serie de artículos son las notas de estudio del autor para aprender "Patrones de diseño de óxido" y sus propios conocimientos. Por lo tanto, la estructura de esta serie de artículos es también la misma que la de este libro (la estructura puede ajustarse más adelante), dividida básicamente en tres partes

  1. gramática idiomática
  2. Patrones de diseño
  3. Anti-patrones (anti_patrones)

Los modismos son estilos, pautas y patrones comunes para la programación en Rust que están ampliamente aceptados por la comunidad. Escribir código idiomático permite que otros desarrolladores entiendan mejor el código que escribes.

Este artículo es el inicio de esta serie de artículos, partiendo de las técnicas habituales de programación de Rust para empezar, correspondientes al libro de patrones de diseño, es decir, el tema de este número es

  1. 使用借用类型作为参数
  2. 格式化字符串
  3. 构造函数

1. Usa tipos prestados como parámetros

El uso de un tipo prestado como parámetro puede evitar la capa de direccionamiento indirecto en el proceso de transferencia de parámetros de función. Por ejemplo, String tiene una capa de direccionamiento indirecto, &String tiene dos capas de direccionamiento indirecto. Podemos evitar esta situación usando &str, y dejar que se llame a &String cuando la función Cast to &str.

En este ejemplo, usamos &String como parámetro de función para comparar con &str.

Esto también se aplica a &Vec<T>with o&[T] with .&Box<T>&T

Tomando prestado un ejemplo del libro, por ejemplo, si queremos determinar si hay tres vocales en una palabra, usamos &String como parámetro para pasar, el código debe escribirse de la siguiente manera

Sonido original: aeiou

fn three_vowels(word: &String) -> bool {
    
    
    let mut vowel_count = 0;
    for c in word.chars() {
    
    
        match c {
    
    
            'a' | 'e' | 'i' | 'o' | 'u' => {
    
    
                vowel_count += 1;
                if vowel_count >= 3 {
    
    
                    return true
                }
            }
            _ => vowel_count = 0
        }
    }
    false
}

fn main() {
    
    
    let ferris = "Ferris".to_string();
    let curious = "Curious".to_string();
    println!("{}: {}", ferris, three_vowels(&ferris));
    println!("{}: {}", curious, three_vowels(&curious));

    // 上面这么写是没有问题的,但是如果写成下面注释里面的样子,就会报错
    // println!("Ferris: {}", three_vowels("Ferris"));
    // println!("Curious: {}", three_vowels("Curious"));

}

Esta situación también es muy común en C++, porque el tipo de parámetro pasado en la firma de la función debe ser &String. Si "Ferris" se pasa directamente, es &str. Cuando se pasa a la función, no se verá forzado a convertir a &String, los amigos que aprenden C ++ deben estar muy familiarizados con este punto, si desea que sea posible pasar parámetros como ese, entonces la firma de la función debe cambiarse así

fn three_vowels(word: &str) -> bool {
    
    

De esta manera, no importa qué tipo de parámetro pasemos, se emitirá el resultado normal.

Ferris: false
Curious: true

Ahora probamos un ejemplo de este tipo, dada una oración, para determinar si cada palabra tiene tres vocales conectadas, para este propósito, cambiamos el código a lo siguiente

fn three_vowels(word: &str) -> bool {
    
    
    let mut vowel_count = 0;
    for c in word.chars() {
    
    
        match c {
    
    
            'a' | 'e' | 'i' | 'o' | 'u' => {
    
    
                vowel_count += 1;
                if vowel_count >= 3 {
    
    
                    return true
                }
            }
            _ => vowel_count = 0
        }
    }
    false
}

fn main() {
    
    
    let sentence_string =
        "Once upon a time, there was a friendly curious crab named Ferris".to_string();
    for word in sentence_string.split(' ') {
    
    
        if three_vowels(word) {
    
    
            println!("{} 有三个连续的元音!", word);
        }
    }
}

Se puede ver que no hemos cambiado la función tres_vocales, pero en el lugar donde se llama a la función, use el método de división para dividir la cadena en varias palabras y pasarlas a la función a su vez. En este momento, los beneficios de &str se reflejan, y el valor devuelto por split Los elementos de la matriz son todos del tipo &str. Es muy simple convertir el tipo String a &str.

2. Cadena de empalme de formato

En términos generales, cuando estemos desarrollando, usaremos los métodos push y push_str del método String para el empalme de cadenas, o usaremos directamente + para lograr el empalme de cadenas, pero a veces puede ser más conveniente usar format!, especialmente una cadena de caracteres mixtos. tipos de cosas

Primero construimos manualmente una cadena

let mut hello = "Hello ".to_owned();
hello.push_str(name);
hello.push('!');

Este es un uso bastante común, ahora usamos formato para construir esta cadena

fn say_hello(name: &str) -> String {
    
    
    format!("Hello {}!", name)
}

formato! devuelve una cadena formateada, {} se usa como marcador de posición, y luego los parámetros se pasan más tarde, y la cadena procesada se puede devolver. Es difícil ver sus beneficios en un lugar tan simple, pero cuando se inserta Cuando hay son muchas cosas, conocerás los beneficios de formatear cadenas.

Esta pieza tiene cosas similares tanto en python como en js. Creo que es fácil de usar en python y js. En js, solo
let hello = `hello ${name}`

En Rust, usar format! para formatear cadenas concatenadas es la forma más concisa y legible.

Tercero, usa el constructor

En Rust, en realidad no existe el concepto de un constructor, pero se puede usar una función asociada convencional new para crear un objeto. como

pub struct Second {
    
    
    value: u64
}

impl Second {
    
    
    // 构建一个Second实例
    // 注意,这是个关联函数,参数里面没有self
    pub fn new(value: u64) -> Self {
    
    
        Self {
    
     value }
    }

    /// 返回秒数,即Second的value
    pub fn value(&self) -> u64 {
    
    
        self.value
    }
}

Creamos una segunda estructura e implementamos el nuevo método para construir un nuevo objeto.

Cuando está en uso, podemos crear un objeto llamando al nuevo método

let s = Second::new(42);

El rasgo predeterminado también se puede implementar en Rust para implementar el constructor predeterminado

impl Default for Second {
    
    
    fn default() -> Self {
    
    
        Self {
    
     value: 0 }
    }
}

Usar derivar para derivar Predeterminado también puede lograr el mismo efecto, por ejemplo, puede escribir

#[derive(Default)]
pub struct Second {
    
    
    value: u64
}

impl Second {
    
    
    pub fn value(&self) -> u64 {
    
    
        self.value
    }
}

En este punto no necesitamos el nuevo método, podemos llamar directamente al método predeterminado para construir la instancia

let s = Second::default();

注意:Se recomienda usar new para crear el constructor. En desarrollo comunitario, new se suele usar para implementar el constructor, porque es más razonable que default y más acorde con los hábitos de lectura. Su función es la misma que default.


Resumir

Esta sección es el primer número del patrón de diseño de Rust e introduce principalmente alguna sintaxis idiomática del patrón de diseño de Rust.

  • Usar tipos prestados como argumentos de función
  • formato de cadena concatenada
  • Constructor

Creo que a través de esta serie de artículos, puedes tener una comprensión más profunda de Rust.


Creé 一起学Rustuna comunidad e invito a los amigos que estén interesados ​​en el óxido a unirse .

 http://t.csdn.cn/AsEZ9 

Supongo que te gusta

Origin blog.csdn.net/weixin_47754149/article/details/126571097
Recomendado
Clasificación