首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >预期类型参数,找到u8,但类型参数是u8

预期类型参数,找到u8,但类型参数是u8
EN

Stack Overflow用户
提问于 2016-05-24 10:17:56
回答 2查看 2.8K关注 0票数 5
代码语言:javascript
运行
复制
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());
}

(游乐场)

以上代码导致以下错误:

代码语言:javascript
运行
复制
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)

我的猜测是,问题来自于特质中的通用功能。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-05-24 10:22:35

下面的代码不符合您的预期

代码语言:javascript
运行
复制
impl Foo for Bar {
    fn foo<u8>(&self) -> u8 {
        self.b
    }
}

它引入了一个名为u8的泛型类型,它隐藏了具体的u8类型。您的功能将100%与

代码语言:javascript
运行
复制
impl Foo for Bar {
    fn foo<T>(&self) -> T {
        self.b
    }
}

在这种情况下,它不能工作,因为T是由foo的调用方选择的,不能保证是u8

要通常解决此问题,请选择不与具体类型名称冲突的泛型类型名称。请记住,实现中的函数签名必须与特征定义中的签名匹配。

为了解决出现的问题,您希望将泛型类型修正为一个特定值,您可以将泛型参数移动到该属性,并仅为u8实现该特征。

代码语言:javascript
运行
复制
trait Foo<T> {
    fn foo(&self) -> T;
}

struct Bar {
    b: u8,
}

impl Foo<u8> for Bar {
    fn foo(&self) -> u8 {
        self.b
    }
}

或者,如果您不希望对特定类型执行多个Foo内嵌(谢谢@MatthieuM),则可以使用相关的特性:

代码语言:javascript
运行
复制
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
    }
}
票数 9
EN

Stack Overflow用户

发布于 2017-04-28 13:00:41

让我们看一个稍微一般一些的例子。我们将定义一个具有接受并返回泛型类型的函数的特性:

代码语言:javascript
运行
复制
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?如果不允许跟踪,您的代码将停止编译!

但是,您应该避免使用现有类型的泛型类型参数--如所示,它只是令人困惑。

很多时候,人们陷入这个陷阱是因为他们试图为一个通用参数指定一个具体的类型。这表明对泛型类型的工作方式存在误解:泛型类型是函数的调用方选择的;实现不能选择它们是什么!

其他答案中概述的解决方案消除了调用方选择泛型的能力。

  • 将泛型类型移到这个特性,并且只对少数几个类型实现它,意味着只有一小部分实现可用。如果调用方试图使用没有相应实现的类型,那么它将无法编译。
  • 选择关联类型是为了允许特征的实现者选择类型,在这种情况下通常是正确的解决方案。

有关两者之间选择的更多细节,请参见什么时候使用关联类型与泛型类型比较合适?

这个问题对于学习锈病的人来说更常见,因为他们还没有将泛型的各种语法进行内化。快速刷新一下..。

职能/方法:

代码语言:javascript
运行
复制
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

特征:

代码语言:javascript
运行
复制
trait Foo<T>
//       ^-^ declares a generic type parameter

结构/枚举:

代码语言:javascript
运行
复制
enum Wuuf<T>
//       ^-^ declares a generic type parameter

struct Quux<T>
//         ^-^ declares a generic type parameter

实现:

代码语言:javascript
运行
复制
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的泛型来回到原来的情况!

代码语言:javascript
运行
复制
impl<u8> Foo<u8> for Bar // Right back where we started

还有一种更罕见的情况:你并不是想让这种类型在任何形式上都是通用的。如果是这样的话,请重命名或删除泛型类型声明,并编写一个标准函数。对于我们的例子来说,如果我们总是想返回一个u8,不管传入的类型是什么,我们只需要写:

代码语言:javascript
运行
复制
trait Foo {
    fn foo<T>(&self, value: T) -> u8;
}

impl Foo for Bar {
    fn foo<T>(&self, value: T) -> u8 {
        42
    }
}

好消息!至少在Rust 1.17中,引入这类错误要容易一些,这要归功于一个警告:

代码语言:javascript
运行
复制
warning: type parameter `u8` should have a camel case name such as `U8`
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37410672

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档