English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Estruturas Rust

No Rust, tanto as estruturas (Struct) quanto os tuplos (Tuple) podem agrupar vários tipos de dados não necessariamente diferentes em um todo, mas cada membro da estrutura e a estrutura em si têm um nome, o que facilita o acesso aos seus membros sem precisar lembrar dos índices. Os tuplos são frequentemente usados para passar múltiplos valores não definidos, enquanto as estruturas são usadas para estruturar estruturas de dados comuns. Cada membro da estrutura é chamado de "campo".

Definição de estrutura

Esta é uma definição de estrutura:

struct Site {
    domain: String,
    name: String,
    nation: String,
    found: u32
}

Atenção: se você usar frequentemente C/C++Lembre-se de que no Rust, a declaração de struct é usada apenas para definição e não para declaração de exemplo, não é necessário o símbolo ; no final, e cada campo definido é separado por ,.

Exemplo de estrutura

Muitos aspectos do Rust são influenciados pelo JavaScript, e a estrutura de tipos é implementada usando a sintaxe de chave: valor de objetos JSON para definição:

let w3codebox = Site {
    domain: String::from("pt.oldtoolbag.com");
    name: String::from("w3codebox),
    nation: String::from("China");
    found: 2013
};

如果你不了解 JSON 对象,你可以不用管它,记住格式就可以了:

结构体类名 {
    字段名 : 字段值,
    ...
}

这样的好处是不仅使程序更加直观,还不需要按照定义的顺序来输入成员的值。

如果正在示例化的结构体有字段名称和现存变量名称一样的,可以简化书写:

let domain = String::from("pt.oldtoolbag.com");
let name = String::from("w3codebox);
let w3codebox = Site {
    domain,  // 等同于 domain : domain,
    name,    // 等同于 name : name,
    nation: String::from("China");
    traffic: 2013
};

有这样一种情况:你想要新建一个结构体的示例,其中大部分属性需要被设置成与现存的一个结构体属性一样,仅需更改其中的一两个字段的值,可以使用结构体更新语法:

let site = Site {
    domain: String::from("pt.oldtoolbag.com");
    name: String::from("w3codebox),
    ..w3codebox
};

注意:..w3codebox 后面不可以有逗号。这种语法不允许一成不变的复制另一个结构体示例,意思就是说至少重新设定一个字段的值才能引用其他示例的值。

元组结构体

有一种更简单的定义和使用结构体的方式:元组结构体

元组结构体是一种形式是元组的结构体。

与元组的区别是它有名字和固定的类型格式。它存在的意义是为了处理那些需要定义类型(经常使用)又不想太复杂的简单数据:

struct Color(u8, u8, u8);
struct Point(f64, f64);
let black = Color(0, 0, 0);
let origin = Point(0.0, 0.0);

“颜色”和“点坐标”是常用的两种数据类型,但如果示例化时写个大括号再写上两个名字就为了可读性牺牲了便捷性,Rust 不会遗留这个问题。元组结构体对象的使用方式和元组一样,通过 . 和下标来进行访问:

fn main() {
    struct Color(u8, u8, u8);
    struct Point(f64, f64);
    let black = Color(0, 0, 0);
    let origin = Point(0.0, 0.0);
    println!("black = ({}, {}, {}),", black.0, black.1, black.2);
    println!("origin = ({}, {}),", origin.0, origin.1);
}

Resultado da execução:

black = (0, 0, 0)
origin = (0, 0)

Propriedade de struct

A struct deve ter domínio sobre a propriedade dos valores dos campos, porque a struct libera todos os campos quando falha.

É por isso que os exemplos deste capítulo usam o tipo String em vez de &str.

Isso não significa que não sejam definidos campos de referência na struct, isso deve ser implementado através do mecanismo de 'vida' (lifecycle).

Mas ainda é difícil explicar o conceito de 'vida' (lifecycle), então só pode ser explicado em capítulos posteriores.

Saída de struct

Em depuração, é muito útil exibir completamente um exemplo de struct. Mas se escrevermos manualmente, pode ser muito inconveniente. Portanto, o Rust oferece um método conveniente para exibir completamente uma struct:

[derive(Debug)]
struct Retângulo {
    width: u32,
    height: u32,
}
fn main() {
    let rect1 = Retângulo { width: 30, height: 50 };
    println!("rect1 é {:?}", rect1);
}

Como mostrado na primeira linha: certifique-se de importar a biblioteca de depuração [derive(Debug)] Depois disso, você pode usar o marcador de posição {:?} em println e print macros para saída completa de uma struct:

rect1 é Rectangle { width: 30, height: 50 }

Se houver muitos atributos, pode usar outro marcador de posição {:#?} .

Resultado de saída:

rect1 é Rectangle {
    width: 30,
    height: 50
}

Métodos de struct

Métodos (Method) e funções (Function) são semelhantes, exceto que são usadas para operar exemplos de structs.

Se você já estudou algumas linguagens orientadas a objetos, você deve estar claro que as funções geralmente são colocadas dentro da definição da classe e são representadas por 'this' para o exemplo operado.

O linguagem Rust não é orientada a objetos, isso pode ser visto pela inovação no mecanismo de propriedade. Mas é possível implementar pensamentos valiosos da orientação a objetos no Rust.

O primeiro parâmetro de um método de struct deve ser '&self', não é necessário declarar o tipo, pois 'self' não é um estilo, mas uma palavra-chave.

Calcular a área de um retângulo:

struct Retângulo {
    width: u32,
    height: u32,
}
    
impl Retângulo {
    fn area(&self) -> u32 {
        self.width * self.height
    }
}
fn main() {
    let rect1 = Retângulo { width: 30, height: 50 };
    println!("rect1's área é {}", rect1.area());
}

Resultado de saída:

rect1's área é 1500

Atenção, ao chamar métodos de structs, não é necessário preencher 'self', isso é devido à consideração da conveniência de uso.

Um exemplo de instância com múltiplos parâmetros:

struct Retângulo {
    width: u32,
    height: u32,
}
impl Retângulo {
    fn area(&self) -> u32 {
        self.width * self.height
    }
    fn wider(&self, rect: &Rectangle) -> bool {}}
        self.width > rect.width
    }
}
fn main() {
    let rect1 = Retângulo { width: 30, height: 50 };
    let rect2 = Retângulo { width: 40, height: 20 };
    println!("{}", rect1.wider(&rect2));
}

Resultado da execução:

false

Este programa calcula rect1 Se for maior que rect2 Mais largo.

Função associada da estrutura

A razão pela qual o "método da estrutura" não é chamado de "função da estrutura" é porque o nome "função" é reservado para essa função: ela está no bloco impl, mas não tem o parâmetro &self.

Essa função não depende do exemplo, mas para usá-la, é necessário declarar em qual bloco impl está.

A função String::from que sempre usamos é uma "função associada".

[derive(Debug)]
struct Retângulo {
    width: u32,
    height: u32,
}
impl Retângulo {
    fn create(width: u32, height: u32) -> Retângulo {
        Retângulo { width, height }
    }
}
fn main() {
    let rect = Rectangle::create(30, 50);
    println!("{:?}", rect);
}

Resultado da execução:

Retângulo { width: 30, height: 50 }

Dica:O bloco impl da estrutura pode ser escrito várias vezes, e o efeito é equivalente à concatenação de seu conteúdo!

Estrutura unitária

A estrutura pode ser apenas um símbolo e não precisa de quaisquer membros:

struct UnitStruct;

Nós chamamos essa estrutura sem corpo de estrutura unitária (Unit Struct).