Objetos de trait e dyn
Despacho dinâmico
Objetos de trait e dyn é uma aula grátis de Learn Rust Coding no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Learn Rust Coding, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Learn Rust Coding inclui 4 aulas no total.
O problema: tipos mistos
Genéricos com restrições de traço funcionam muito bem quando cada chamada usa um único tipo concreto. Mas e se você quiser uma coleção de tipos diferentes que compartilham um traço? Os genéricos não podem conter uma mistura.
Objetos de traço resolvem isso.
O que é um objeto de traço?
Um objeto de traço é um valor referenciado por meio de um ponteiro junto com a palavra-chave dyn, como &dyn Trait ou Box<dyn Trait>.
Ele permite tratar muitos tipos concretos de maneira uniforme durante a execução.
Uma Box de dyn Trait
Box<dyn Trait> possui um valor na memória heap de algum tipo que implementa o traço. Você chama métodos do traço sem conhecer o tipo concreto.
trait Speak { fn say(&self) -> String; }
struct Dog;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }
fn main() {
let animal: Box<dyn Speak> = Box::new(Dog);
println!("{}", animal.say());
}Um Vec de objetos de traço
A grande vantagem: um único vetor pode conter muitos tipos diferentes, desde que cada um implemente o traço.
trait Speak { fn say(&self) -> String; }
struct Dog;
struct Cat;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }
impl Speak for Cat { fn say(&self) -> String { String::from("Meow") } }
fn main() {
let zoo: Vec<Box<dyn Speak>> = vec![Box::new(Dog), Box::new(Cat)];
for animal in &zoo {
println!("{}", animal.say());
}
}Despacho dinâmico
Com objetos de traço, o método a ser chamado é escolhido durante a execução, consultando uma tabela oculta, a vtable. Isso é chamado de despacho dinâmico.
O custo é uma pequena indireção; o benefício é a flexibilidade durante a execução.
Funções que retornam objetos de traço
Uma função pode retornar Box<dyn Trait> quando o tipo concreto varia. Isso é útil para funções de fábrica que decidem o tipo durante a execução.
trait Speak { fn say(&self) -> String; }
struct Dog;
struct Cat;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }
impl Speak for Cat { fn say(&self) -> String { String::from("Meow") } }
fn make(kind: &str) -> Box<dyn Speak> {
if kind == "dog" { Box::new(Dog) } else { Box::new(Cat) }
}
fn main() {
println!("{}", make("cat").say());
}Objetos de traço emprestados
Você também pode passar um objeto de traço emprestado com &dyn Trait quando não precisa de propriedade. Nenhuma alocação na memória heap é feita.
trait Speak { fn say(&self) -> String; }
struct Dog;
impl Speak for Dog { fn say(&self) -> String { String::from("Woof") } }
fn announce(s: &dyn Speak) {
println!("heard: {}", s.say());
}
fn main() {
let d = Dog;
announce(&d);
}Segurança para objetos
Nem todo traço pode ser um objeto de traço. Um traço precisa ser seguro para objetos: em termos gerais, seus métodos não podem retornar Self por valor nem usar parâmetros de tipo genéricos.
Métodos que recebem &self e usam tipos concretos são válidos.
Um exemplo que não é seguro para objetos
Um traço com um método que retorna Self não pode ser usado como dyn, pois o tamanho de Self é desconhecido atrás de um ponteiro. Mantenha simples os traços usados como objetos.
Um exemplo no estilo de plug-in
Os objetos de traço são excelentes para sistemas de plug-ins: armazene uma lista de manipuladores atrás de dyn e execute todos sem se preocupar com os tipos concretos.
trait Task { fn run(&self) -> i32; }
struct Add { a: i32, b: i32 }
struct Negate { x: i32 }
impl Task for Add { fn run(&self) -> i32 { self.a + self.b } }
impl Task for Negate { fn run(&self) -> i32 { -self.x } }
fn main() {
let tasks: Vec<Box<dyn Task>> = vec![Box::new(Add { a: 2, b: 3 }), Box::new(Negate { x: 7 })];
let total: i32 = tasks.iter().map(|t| t.run()).sum();
println!("total {}", total);
}Quando usar dyn
Use objetos de traço quando precisar de coleções heterogêneas, de tipos escolhidos durante a execução ou de reduzir o excesso de código causado por muitas instanciações genéricas.
Caso contrário, prefira genéricos para obter a máxima velocidade.
Verificação rápida
Teste sua compreensão sobre objetos de traço.
Recapitulação
Você aprendeu sobre despacho dinâmico:
- Objetos de traço usam
dynatrás de um ponteiro (Box<dyn T>,&dyn T) - Eles permitem coleções heterogêneas e tipos escolhidos durante a execução
- As chamadas de método passam por uma vtable (despacho dinâmico)
- Os traços precisam ser seguros para objetos para serem usados dessa forma
Perguntas Frequentes
A aula “Objetos de trait e dyn” é grátis?
Sim — o texto completo de “Objetos de trait e dyn” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Learn Rust Coding, atualize para CoddyKit PRO. O curso de Learn Rust Coding inclui 4 aulas no total.
O que vou aprender em “Objetos de trait e dyn”?
Despacho dinâmico Você pratica Learn Rust Coding com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Learn Rust Coding?
Nenhuma experiência prévia é necessária. Learn Rust Coding no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Objetos de trait e dyn”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Learn Rust Coding?
Sim. Cada aula de Learn Rust Coding inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Definição de traits
- Objetos de trait e dyn
- Despacho estático versus dinâmico
- Métodos padrão