[Aprenda Rust juntos | Padrões de design] Gramática idiomática - traço padrão, ponteiro inteligente de coleção, destruidor


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.

Este artigo apresenta principalmente a gramática idiomática no padrão de design Rust

  • característica padrão
  • ponteiro inteligente de coleção
  • destruidor

默认特质:No desenvolvimento do Rust, o novo método não pode ser exigido em todos os lugares. Para resolver esse problema, o recurso Default é implementado. Além disso, ele também pode ser usado com outros contêineres.

集合智能指针:Use o recurso Deref para transformar coleções em ponteiros inteligentes, fornecendo exibições próprias e emprestadas dos dados.

析构函数:Rust não fornece código que será executado, não importa como a função saia. No entanto, o destruidor de um objeto pode ser usado para executar o código que deve ser executado antes de sair.


1. Características padrão

No Rust, muitos tipos possuem um construtor, porém isso é específico para um determinado tipo. Rust não impõe que todo tipo deva ter um novo método como construtor. Para atender a esse requisito, o Rust fornece o traço Padrão, que pode ser usado com outros contêineres.

注意:Alguns contêineres já implementam o recurso Padrão no local.

Um contêiner de elemento único como Cow, Box ou Arc pode não apenas implementar valores padrão para os tipos padrão contidos, mas também #[derive(Default)] automaticamente sua estrutura para todos os campos, portanto, quanto mais tipos implementarem valores padrão , Mais útil é.

Por outro lado, o construtor pode aceitar vários parâmetros enquanto o método default() não pode. Pode até haver vários construtores com nomes diferentes, mas apenas uma implementação padrão por tipo.

O seguinte é um exemplo

use std::{
    
    path::PathBuf, time::Duration};

// 导出默认值
#[derive(Default, Debug, PartialEq)]
struct MyConfiguration {
    
    
    // 选项默认为“None”
    output: Option<PathBuf>,
    // 默认空向量
    search_path: Vec<PathBuf>,
    // 持续时间默认为0
    timeout: Duration,
    // 布尔值默认为Flase
    check: bool,
}

impl MyConfiguration {
    
    
    // 在这添加setter
}

fn main() {
    
    
    // 构建一个拥有默认值的新实例
    let mut conf = MyConfiguration::default();
    // 做一些处理操作
    conf.check = true;
    println!("conf = {:#?}", conf);
        
    // 部分初始化创建实例
    let conf1 = MyConfiguration {
    
    
        check: true,
        ..Default::default()
    };
    assert_eq!(conf, conf1);
}

2. Defina ponteiros inteligentes

Use o recurso Deref para transformar coleções em ponteiros inteligentes, fornecendo exibições próprias e emprestadas dos dados. O seguinte é um exemplo de uso.

use std::ops::Deref;

struct Vec<T> {
    
    
    data: RawVec<T>,
    //..
}

impl<T> Deref for Vec<T> {
    
    
    type Target = [T];

    fn deref(&self) -> &[T] {
    
    
        //..
    }
}

Vect<T> é uma coleção que possui T, &[T] é uma coleção que empresta T, implementar o traço Deref para Vec permitirá desreferenciar implícito de &Vec<T> para &[T]>

Assim como String e &str, você pode se referir a ele.

Propriedade e empréstimo são aspectos-chave da linguagem Rust. Para fornecer uma boa experiência ao usuário, as estruturas de dados devem levar em conta essa semântica. Ao implementar uma estrutura de dados que possui seus dados, fornecer uma visão emprestada desses dados permite uma API mais flexível.

A maioria dos métodos só pode ser implementada para a exibição emprestada e, em seguida, eles estão implicitamente disponíveis para a exibição proprietária. Deixe os clientes escolherem entre tomar emprestado ou se apropriar dos dados.

注意:Métodos e características disponíveis apenas por meio de desreferenciação não são considerados para verificação de limites, portanto, a programação genérica de estruturas de dados usando esse padrão pode se tornar complicada (consulte características Borrow e AsRef, etc.).

3. Destruidor

Rust não fornece código que será executado, não importa como a função saia. No entanto, o destruidor de um objeto pode ser usado para executar o código que deve ser executado antes de sair.

O seguinte é um exemplo de uso

fn bar() -> Result<(), ()> {
    
    
    // 这些不是必须要在函数中定义的,也可以在其他地方定义
    struct Foo;

    // 为Foo实现析构函数
    impl Drop for Foo {
    
    
        fn drop(&mut self) {
    
    
            println!("exit");
        }
    }

    // _exit的dtor将在退出函数“bar”时运行。
    let _exit = Foo;
    // 用?操作符隐式的返回
    baz()?;
    // 正常返回
    Ok(())
}

Se uma função tiver vários pontos de retorno, torna-se difícil e repetitivo (e, portanto, sujeito a erros) executar o código na saída. Isso é especialmente verdadeiro se o retorno for implícito devido a uma macro. Qual é a situação comum? operador, retorna se o resultado for Err, mas continua se o resultado for Ok? é usado como um mecanismo de tratamento de exceções, mas ao contrário do Java (que acabou sendo implementado), não há como agendar o código para ser executado em condições normais e excepcionais. O pânico também sairá da função mais cedo.

O código no destruidor (quase) sempre será executado para lidar com pânicos, retornos antecipados, etc.


Resumir

O acima é todo o conteúdo deste artigo, apresentando as três partes da gramática idiomática no padrão de design Rust

  • característica padrão
  • ponteiro inteligente de coleção
  • destruidor

Através do conteúdo desta edição, espero que você possa ter uma compreensão mais profunda do desenvolvimento Rust.

Acho que você gosta

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