trait Foo {
fn foo<T>(&self) -> T;
}
struct Bar {
b: u8,
}
impl Foo for Bar {
fn foo<u8>(&self) -> u8 {
self.b
}
}
fn main() {
let bar = Bar {
b: 2,
};
println!("{:?}", bar.foo());
}
(游乐场)
以上代码导致以下错误:
error[E0308]: mismatched types
--> <anon>:11:9
|
11 | self.b
| ^^^^^^ expected type parameter, found u8
|
= note: expected type `u8` (type parameter)
found type `u8` (u8)
我的猜测是,问题来自于特质中的通用功能。
发布于 2016-05-24 10:22:35
下面的代码不符合您的预期
impl Foo for Bar {
fn foo<u8>(&self) -> u8 {
self.b
}
}
它引入了一个名为u8
的泛型类型,它隐藏了具体的u8
类型。您的功能将100%与
impl Foo for Bar {
fn foo<T>(&self) -> T {
self.b
}
}
在这种情况下,它不能工作,因为T
是由foo
的调用方选择的,不能保证是u8
。
要通常解决此问题,请选择不与具体类型名称冲突的泛型类型名称。请记住,实现中的函数签名必须与特征定义中的签名匹配。
为了解决出现的问题,您希望将泛型类型修正为一个特定值,您可以将泛型参数移动到该属性,并仅为u8
实现该特征。
trait Foo<T> {
fn foo(&self) -> T;
}
struct Bar {
b: u8,
}
impl Foo<u8> for Bar {
fn foo(&self) -> u8 {
self.b
}
}
或者,如果您不希望对特定类型执行多个Foo
内嵌(谢谢@MatthieuM),则可以使用相关的特性:
trait Foo {
type T;
fn foo(&self) -> T;
}
struct Bar {
b: u8,
}
impl Foo for Bar {
type T = u8;
fn foo(&self) -> u8 {
self.b
}
}
发布于 2017-04-28 13:00:41
让我们看一个稍微一般一些的例子。我们将定义一个具有接受并返回泛型类型的函数的特性:
trait Foo {
fn foo<T>(&self, value: T) -> T;
}
struct Bar;
impl Foo for Bar {
fn foo<u8>(&self, value: u8) -> u8 {
value
}
// Equivalent to
// fn foo<T>(&self, value: T) -> T {
// value
// }
}
作为布克已经解释过了,fn foo<u8>(&self, value: u8) -> u8
定义了一个名为u8
的泛型类型参数,该参数隐藏内置的u8
类型。这是允许的,因为转发兼容性的原因-如果您决定调用您的通用类型Fuzzy
,然后调用一个机箱(或标准库!)介绍了一种类型,也称为Fuzzy
?如果不允许跟踪,您的代码将停止编译!
但是,您应该避免使用现有类型的泛型类型参数--如所示,它只是令人困惑。
很多时候,人们陷入这个陷阱是因为他们试图为一个通用参数指定一个具体的类型。这表明对泛型类型的工作方式存在误解:泛型类型是函数的调用方选择的;实现不能选择它们是什么!
其他答案中概述的解决方案消除了调用方选择泛型的能力。
有关两者之间选择的更多细节,请参见什么时候使用关联类型与泛型类型比较合适?。
这个问题对于学习锈病的人来说更常见,因为他们还没有将泛型的各种语法进行内化。快速刷新一下..。
职能/方法:
fn foo<T>(a: T) -> T
// ^-^ declares a generic type parameter
fn foo<T>(a: T) -> T
// ^ ^ a type, which can use a previously declared parameter
特征:
trait Foo<T>
// ^-^ declares a generic type parameter
结构/枚举:
enum Wuuf<T>
// ^-^ declares a generic type parameter
struct Quux<T>
// ^-^ declares a generic type parameter
实现:
impl<T> Foo<T> for Bar<T>
// ^-^ declares a generic type parameter
impl<T> Foo<T> for Bar<T>
// ^----^ ^----^ a type, which can use a previously declared parameter
在这些示例中,只允许类型指定具体类型,这就是为什么impl Foo<u8> for Bar
是有意义的。您也可以通过在一个特性上声明一个名为u8
的泛型来回到原来的情况!
impl<u8> Foo<u8> for Bar // Right back where we started
还有一种更罕见的情况:你并不是想让这种类型在任何形式上都是通用的。如果是这样的话,请重命名或删除泛型类型声明,并编写一个标准函数。对于我们的例子来说,如果我们总是想返回一个u8
,不管传入的类型是什么,我们只需要写:
trait Foo {
fn foo<T>(&self, value: T) -> u8;
}
impl Foo for Bar {
fn foo<T>(&self, value: T) -> u8 {
42
}
}
好消息!至少在Rust 1.17中,引入这类错误要容易一些,这要归功于一个警告:
warning: type parameter `u8` should have a camel case name such as `U8`
https://stackoverflow.com/questions/37410672
复制相似问题