El despacho es el mecanismo para seleccionar una función (método) específica para llamar. En Rust hay dos enfoques: despacho estático y dinámico.
Historia del tema:
En los lenguajes orientados a objetos, se utiliza generalmente una vtable (tabla virtual) para la llamada dinámica de métodos. En Rust, un equivalente se implementa para los trait objects: referencias a objetos de tipos que implementan ciertos traits. El despacho estático se produce al usar generics y límites de traits.
Problema:
A menudo se debe elegir entre flexibilidad (con la capacidad de trabajar con objetos de diferentes tipos a través de una única interfaz) y rendimiento (el despacho estático permite la integración de métodos). Una elección incorrecta lleva a generics excesivamente complejos o a pérdidas de rendimiento.
Solución:
El despacho estático se logra a través de parámetros genéricos: en este caso, el compilador genera código separado para cada tipo. El dinámico — si una función acepta un argumento del tipo &dyn Trait o Box<dyn Trait>, entonces al llamar un método del trait, Rust mira en la vtable por dirección, como en los lenguajes OOP clásicos.
Ejemplo de código:
trait Shape { fn area(&self) -> f64; } impl Shape for Circle { fn area(&self) -> f64 { 3.1415 * self.radius * self.radius } } fn print_area(shape: &dyn Shape) { // despacho dinámico println!("area = {}", shape.area()); } // O estáticamente: fn print_area_static<S: Shape>(shape: &S) { println!("area = {}", shape.area()); }
Características clave:
dyn Trait utiliza vtable (despacho dinámico)¿Se puede hacer Box<dyn Sized>?
No. dyn Trait por definición es unsized, siempre requiere el uso de Box, Arc o referencias, pero no “Box<dyn Sized>” — eso no tiene sentido. Los trait objects no tienen el trait Sized.
¿Está permitido dyn Trait para traits con métodos genéricos?
No. No se pueden hacer traits object-safe con métodos genéricos (¡a menudo se confunde!), los tipos compuestos no son object-safe:
trait MyTrait { fn foo<T>(&self, x: T); } let x: &dyn MyTrait = ... // ¡Error de compilación!
¿Se puede hacer dyn Trait para un trait con Self en la firma?
No se puede, si el método devuelve Self (muchos no entienden este matiz: la seguridad del objeto exige que no haya Self en la firma; se puede usar self solo en argumentos, pero no en valores de retorno).
Se utilizó dyn Trait en todas partes por la universalidad de las interfaces, incluso dentro de bucles ajustados, donde se podrían haber utilizado generics.
Ventajas:
Desventajas:
El despacho estático se aplicó en la lógica interna, mientras que dyn Trait solo se utilizó en los límites de los módulos.
Ventajas:
Desventajas: