[Aprenda Rust juntos | Padrões de design] Gramática idiomática - usando tipos emprestados como parâmetros, formatação e concatenação de strings e construtores

Dica: Depois que o artigo for escrito, o índice pode ser gerado automaticamente. Como gerá-lo pode consultar o documento de ajuda à direita


prefácio

Rust não é uma linguagem de programação tradicional orientada a objetos e todos os seus recursos a tornam única. Portanto, é necessário aprender padrões de design específicos do Rust. Esta série de artigos são as notas de estudo do autor para aprender "Padrões de design de ferrugem" e suas próprias percepções. Portanto, a estrutura desta série de artigos também é a mesma deste livro (a estrutura pode ser ajustada posteriormente), dividida basicamente em três partes

  1. gramática idiomática
  2. Padrões de design
  3. Antipadrões (anti_patterns)

Idiomas são estilos, diretrizes e padrões comuns para programação em Rust que são amplamente aceitos pela comunidade. Escrever código idiomático permite que outros desenvolvedores entendam melhor o código que você escreve.

Este artigo é o início desta série de artigos, partindo das técnicas de programação habituais do Rust para começar, correspondendo ao livro sobre padrões de projeto, ou seja, o tema desta edição é

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

1. Use tipos emprestados como parâmetros

Usar um tipo emprestado como parâmetro pode evitar a camada de indireção no processo de passagem de parâmetro de função. Por exemplo, String tem uma camada de indireção, &String tem duas camadas de indireção. Podemos evitar essa situação usando &str e deixar &String ser chamado quando a função Cast to &str.

Neste exemplo, usamos &String como um parâmetro de função para comparar com &str.

Isso também se aplica a &Vec<T>com ou&[T] com .&Box<T>&T

Pegando emprestado um exemplo do livro, por exemplo, se quisermos determinar se existem três vogais em uma palavra, usamos &String como parâmetro para passar, o código deve ser escrito da seguinte forma

Som 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"));

}

Essa situação também é muito comum em C++, pois o tipo de parâmetro passado na assinatura da função deve ser &String. Se "Ferris" for passado diretamente, é &str. Quando for passado para a função, não será forçado a converter para &String, amigos que aprendem C++ devem estar muito familiarizados com este ponto, se você quiser tornar possível passar parâmetros como esse, então a assinatura da função deve ser alterada assim

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

Desta forma, não importa que tipo de parâmetro passemos, o resultado normal será emitido

Ferris: false
Curious: true

Agora, tentamos esse exemplo, dada uma frase, para determinar se cada palavra tem três vogais conectadas; para esse fim, alteramos o código para o seguinte

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

Pode-se ver que não alteramos a função three_vowels, mas no local onde a função é chamada, use o método split para dividir a string em várias palavras e passá-las para a função por sua vez. Neste momento, os benefícios de &str são refletidos e o valor retornado por split Os elementos na matriz são todos do tipo &str. É muito simples converter o tipo String para &str.

2. Formate a sequência de emenda

De um modo geral, quando estamos desenvolvendo, usaremos os métodos push e push_str do método String para emenda de strings, ou usaremos diretamente + para conseguir emenda de strings, mas às vezes pode ser mais conveniente usar format!, especialmente Uma string de mistura tipos de coisas.

Primeiro, construímos manualmente uma string

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

Este é um uso bastante comum, agora usamos formatação para construir esta string

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

format! retorna uma string formatada, {} é usado como um espaço reservado e, em seguida, os parâmetros são passados ​​posteriormente e a string processada pode ser retornada. É difícil ver seus benefícios em um local tão simples, mas quando inserido Quando há são muitas coisas, você conhecerá os benefícios de formatar strings.

Esta peça tem coisas semelhantes em python e js. Acho que é fácil de usar em python e js. Em js,
deixe apenas hello = `hello ${name}`

No Rust, usar format! para formatar strings concatenadas é a maneira mais concisa e legível.

Em terceiro lugar, use o construtor

No Rust, na verdade, não existe um conceito de construtor, mas uma função associada convencional new pode ser usada para criar um 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
    }
}

Criamos uma estrutura Second e implementamos o novo método para construir um novo objeto.

Quando em uso, podemos criar um objeto chamando o novo método

let s = Second::new(42);

O traço padrão também pode ser implementado em Rust para implementar o construtor padrão

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

Usar derivar para derivar Padrão também pode obter o mesmo efeito, por exemplo, você pode escrever

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

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

Neste ponto, não precisamos do novo método, podemos chamar diretamente o método padrão para criar a instância

let s = Second::default();

注意:É recomendado que você use new para criar o construtor.No desenvolvimento da comunidade, new é geralmente usado para implementar o construtor, por ser mais razoável que o padrão e mais de acordo com os hábitos de leitura.Sua função é a mesma do padrão.


Resumir

Esta seção é a primeira edição do padrão de projeto Rust. Ela apresenta principalmente algumas sintaxes idiomáticas do padrão de projeto Rust.

  • Use tipos emprestados como argumentos de função
  • string concatenada de formato
  • Construtor

Acredito que através desta série de artigos, você possa ter uma compreensão mais profunda do Rust.


Criei 一起学Rustuma comunidade e convido os amigos interessados ​​em ferrugem a se juntarem .

 http://t.csdn.cn/AsEZ9 

Acho que você gosta

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