Reputation: 4610
I get a expected type parameter, even though I think I have returned the correct type data.I am in the learning phase of generic material in rust.
struct Cat {
weight: i32,
}
trait Animal{
fn get_weight<T>(&self) -> T;
}
impl Animal for Cat {
fn get_weight<i32>(&self) -> i32 {
self.weight // I got error in here
}
}
fn main() {}
Error message:
mismatched types
expected type parameter, found i32
note: expected type `i32` (type parameter)
found type `i32` (i32)
expected `i32` because of return type
expected type parameter, found i32
Upvotes: 4
Views: 967
Reputation: 10464
Looking at the compiler warning here is very helpful.
warning: type parameter `i32` should have an upper camel case name
--> src/main.rs:10:19
|
10 | fn get_weight<i32>(&self) -> i32 {
| ^^^ help: convert the identifier to upper camel case: `I32`
|
= note: #[warn(non_camel_case_types)] on by default
As you can see, the i32
between the brackets is being parsed as a type parameter. I believe this locally shadows the type i32
(specifically, the return type is this generic type), so when you return a normal i32
, the compiler complains. This isn't really relevant, since that isn't the root of the problem.
The problem here is that the Animal
trait requires that its get_weight
method be generic in T
. When you implement the trait, you have to provide a get_weight
method that works for every possible type T
(with the implicit restriction that the type is Sized
). This should be impossible, since you'd have to produce an element of any given type out of thin air. Some types don't even have any elements!
Instead, you have two choices. First, you could make a generic trait. The syntax for this is
trait Animal<T> {
fn get_weight(&self) -> T;
}
Note that T
is introduced with the trait, rather than on the method. With this setup, you conceptually don't have a single trait anymore, but rather one trait for every type (again with implicit Sized
bounds). That means that a given type can implement the trait for different values of T
. Like you might have both Animal<i32>
and Animal<u32>
implemented forCat
.
If you still want each type to only implement the trait once and have a single output type, you can use an associated type. The syntax for this is
trait Animal{
type Weight;
fn get_weight(&self) -> Self::Weight;
}
Now when you implement this trait on a type, you have to provide the output type. You could implement Cat
by adding the line type Weight = i32;
inside the trait implementation. Then the get_weight
method would simply need to return i32
, just like what you have already.
Upvotes: 6