I am trying to make adapters around 2 different types that do the same job and I cannot rewrite the two types.
X
has a method which consumes self
so a run-time polymorphic wrapper is not applicable. The only option is a static generic approach.
struct X {}
impl X {
fn f(self, n: i32) {
println!("n = {}", n);
}
fn new() -> X {
X {}
}
}
struct AdapterX {
x: X
}
impl AdapterX {
fn uf(self, n: i32) {
self.x.f(n)
}
fn new(x: X) -> AdapterX {
AdapterX { x: x }
}
}
fn useAdapted<T>(a: T) {
a.uf(10)
}
fn main() {
let x = X::new();
useAdapted::<AdapterX>(AdapterX::new(x));
}
The compiler fails with:
error: no method named `uf` found for type `T` in the current scope
a.uf(10)
^~
The problem is here:
fn useAdapted<T>(a: T) {
a.uf(10)
}
This says
give me any possible type, and I will call the uf
method on it
That's clearly nonsense, as you could pass in a String
or bool
or HashMap
or a File
or a .... (you get the point).
There's no method uf
that applies to every type, so the compiler tells you so. As you discovered, you have to provide a bound on the generic type with one or more traits. Methods and associated functions from those traits will be usable inside the method.
Also note that the Rust style is snake_case
; the function should be called use_adapted
.
I was able to figure it out; the wrapper struct is not needed. The right way is a generic trait. I also missed the type scope for the generic type variable.
struct X {}
impl X {
fn f(self, n: i32) {
println!("n = {}", n);
}
fn new() -> X {
X {}
}
}
trait Adapter<T> {
fn uf(self, n: i32);
}
impl Adapter<X> for X {
fn uf(self, n: i32) {
self.f(n)
}
}
struct Y {}
impl Y {
fn g(self, n: f32) {
println!("m = {}", n);
}
fn new() -> Y {
Y {}
}
}
impl Adapter<Y> for Y {
fn uf(self, n: i32) {
self.g(n as f32)
}
}
fn use_adapted<A, T: Adapter<A>>(a: T) {
a.uf(10)
}
fn main() {
use_adapted(X::new());
use_adapted(Y::new());
}