Tópicos avançados em Tipos
Clube do Livro #19
Padrão NewType
- Legibilidade do código: evita confusão ao introduzir um novo tipo que o compilador nos obriga a usar
struct Meters(u32);
struct SquareMeters(u32);
fn area(width: Meters, height: Meters) -> SquareMeters {
//
}- Legibilidade do código: tipos explícitos para os parâmetros facilitam uso e manutenção
- Uso especial de uma estrutura-tupla (tupple struct)
Clube do Livro #19
Padrão NewType
use std::collections::HashMap;
#[derive(Debug)]
struct People(HashMap<usize, String>);
impl People {
fn new() -> Self {
return Self(HashMap::new());
}
fn add(&mut self, name: String) -> bool {
let does_contain = self.0.values().any(|val| *val == name);
if !does_contain {
self.0.insert(self.0.len() + 1, name);
}
!does_contain
}
}
fn main() {
let mut people = People::new();
people.add(String::from("Fulano"));
let result2 = people.add(String::from("Fulano"));
assert_eq!(false, result2);
people.add(String::from("Ciclano"));
people.add(String::from("Beltrano"));
println!("{:#?}", people)
}
- Nos permite abstrair (simplificar ou ocultar) o funcionamento de um tipo mais complexo:
Clube do Livro #19
Sinônimos (type)
- Apelidos para tipos já definidos
- Podem ser simples ou compostos:
// um simples apelido para o tipo i32
type Kilometers = i32;
// um caso mais complexo de um trait object com lifetime
type Thunk = Box<dyn Fn() + Send + 'static>;
- Principal uso: redução de repetição de código, indicação clara do tipo a ser usado (manutenabilidade), interface comum
- Não é um tipo diferente como acontece no padrão NewType
Clube do Livro #19
Sinônimos (type)
use std::fmt;
use std::io::Error;
pub trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize, Error>;
fn flush(&mut self) -> Result<(), Error>;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Error>;
fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Error>;
}
// O mesmo código com o sinônimo:
type Result<T> = std::result::Result<T, std::io::Error>;
pub trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize>;
fn flush(&mut self) -> Result<()>;
fn write_all(&mut self, buf: &[u8]) -> Result<()>;
fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()>;
}Clube do Livro #19
O tipo que nunca retorna (!)
- Tipo especial no rust para indicar uma função que nunca retorna, isto é, uma função divergente
use std::process::exit;
fn the_answer() -> ! {
exit(42);
}- Sofre coerção para qualquer outro tipo (análise sintática):
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
Clube do Livro #19
Trait sized e DSTs
- Dynamically sized types (DST): tipos com tamanho dinamicamente alocado: tamanho dos tipos somente pode ser determinado em tempo de execução
- Sempre são implementados com ponteiros
- O exemplo mais clássico é o &str
fn main() {
let s1: str = "Hello there!";
let s2: str = "How's it going?";
}- É impossível criar uma variável que guarde um DST
- Em Rust DSTs sempre são criados através de ponteiros inteligentes: uma estrutura que guarda o tamanho dos dados e um ponteiro para os dados na heap
Clube do Livro #19
Trait sized e DSTs
- Traits são DSTs que podem ser referenciadas pelo nome
- O Rust tem uma trait chamada Sized, que é implementada automaticamente em todos os tipos cujo tamanho sabemos em tempo de compilação
- Além disso, Rust adiciona essa trait automaticamente (trait bound) a todas as funções que lidam com genéricos:
fn generic<T>(t: T) {
// código
}
// é o mesmo que:
fn generic<T: Sized>(t: T) {
// código
}Clube do Livro #19
Trait sized e DSTs
- Por padrão, funções genéricas somente trabalharão com tipos que implementam a trait Sized, mas você pode relaxar esse requisito com o código abaixo:
fn generic<T: ?Sized>(t: &T) {
// código
}- O código acima indica que T pode ser um tipo com tamanho conhecido ou não em tempo de compilação. Admitindo a segunda possibilidade, neste caso usamos uma referência (um tipo de ponteiro) para o tipo, pois DSTs sempre são acessadas através de ponteiros
Clube do Livro #19
Obrigado, pessoal!

@felubra
twitter, github, telegram:
Referências
Clube do Livro #19
Advanced Types
By Felipe Lube de Bragança
Advanced Types
Material de apoio para apresentação do capítulo 15 do Livro do Rust em nosso canal do youtube, dia 24/01/2021 às 21h.
- 60