% Sintaxis Universal de Llamadas a Función
Algunas veces, varias funciones pueden tener el mismo nombre. Considera el siguiente código:
trait Foo {
fn f(&self);
}
trait Bar {
fn f(&self);
}
struct Baz;
impl Foo for Baz {
fn f(&self) { println!("impl de Foo en Baz"); }
}
impl Bar for Baz {
fn f(&self) { println!("impl de Bar en Baz"); }
}
let b = Baz;
Si intentaramos llamar b.f()
, obtendriamos un error:
error: multiple applicable methods in scope [E0034]
b.f();
^~~
note: candidate #1 is defined in an impl of the trait `main::Foo` for the type
`main::Baz`
fn f(&self) { println!("Baz’s impl of Foo"); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: candidate #2 is defined in an impl of the trait `main::Bar` for the type
`main::Baz`
fn f(&self) { println!("Baz’s impl of Bar"); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Necesitamos una forma de eliminar la ambigüedad. Esta característica es denominada ‘sintaxis universal de llamadas a función’, y luce así:
# trait Foo {
# fn f(&self);
# }
# trait Bar {
# fn f(&self);
# }
# struct Baz;
# impl Foo for Baz {
# fn f(&self) { println!("impl de Foo en Baz"); }
# }
# impl Bar for Baz {
# fn f(&self) { println!("impl de Bar en Baz"); }
# }
# let b = Baz;
Foo::f(&b);
Bar::f(&b);
Analicémoslo por partes.
Foo::
Bar::
Dichas mitades de invocacion son los tipos de los traits: Foo
y Bar
. Lo anterior es responsable de la eliminación de la ambigüedad entre las dos llamadas: Rust llama la función del trait que nombraste.
f(&b)
Cuando llamamos un método de la forma b.f()
usando la sintaxis de métodos, Rust automáticamente tomara prestado a b
si f()
recibe a &self
. En este caso, Rust no puede hacerlo. Es por ello que debemos pasar a &b
de manera explicita.
Usando <>
La forma de SULF de la que acabamos de hablar:
Trait::metodo(args);
Es una version corta. Existe una version expandida que puede ser necesaria en algunas situaciones:
::metodo(args);
La sintaxis <>::
es una forma de proporcionar una pista de tipos. El tipo va dentro de los <>
s. En este caso es Type as Trait
indicando que deseamos llamar a la version Trait
de metodo
. La sección as Trait
es opcional de no ser ambigua. Lo mismo con los <>
s, de allí proviene version mas corta.
Acá un ejemplo del uso de la forma mas larga.
trait Foo {
fn clone(&self);
}
#[derive(Clone)]
struct Bar;
impl Foo for Bar {
fn clone(&self) {
println!("Creando un clon de Bar");
<Bar as Clone>::clone(self);
}
}
Lo anterior llamara el metodo clone
en el trait Clone
, en vez de la version clone
del trait Foo
.