我得到了预期的类型参数,即使我认为我已经返回了正确的类型数据

时间:2019-07-19 03:21:52

标签: types rust traits

即使我认为已经返回了正确的类型数据,我也得到了预期的类型参数。我正处于锈蚀通用材料的学习阶段。

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() {}

错误消息:

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

1 个答案:

答案 0 :(得分:6)

在这里查看编译器警告非常有帮助。

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

如您所见,括号之间的i32被解析为类型参数。我相信这会局部遮盖类型i32(特别是返回类型就是这种通用类型),因此,当您返回普通的i32时,编译器会抱怨。这并不是真的相关,因为这不是问题的根源。

这里的问题是Animal特性要求其get_weight方法在T中是通用的。在实现特征时,必须提供一个get_weight方法,该方法适用于每种可能的类型T(类型为Sized的隐式限制) 。这应该是不可能的,因为您必须凭空产生任何给定类型的元素。有些类型甚至没有任何元素!

相反,您有两种选择。首先,您可以创建一个通用特征。语法是

trait Animal<T> {
    fn get_weight(&self) -> T;
}

请注意,T是用特征而不是方法引入的。使用此设置,从概念上讲,您不再具有单个特征,而是每个类型都具有一个特征(同样具有隐式Sized界限)。这意味着给定的类型可以为T的不同值实现特征。就像您可能同时为Animal<i32>实现了Animal<u32>Cat

如果仍然希望每个类型仅实现一次特征并具有单个输出类型,则可以使用关联的类型。语法是

trait Animal{
    type Weight;

    fn get_weight(&self) -> Self::Weight;
}

现在,当在类型上实现此特征时,必须提供输出类型。您可以通过在trait实现中添加行Cat来实现type Weight = i32;。然后,get_weight方法只需要返回i32,就像您已经拥有的一样。