【问题标题】:How do I implement a trait with a generic method?如何使用泛型方法实现特征?
【发布时间】:2019-04-04 17:34:45
【问题描述】:

我正在尝试实现一个包含通用方法的特征。

trait Trait {
    fn method<T>(&self) -> T;
}

struct Struct;

impl Trait for Struct {
    fn method(&self) -> u8 {
        return 16u8;
    }
}

我明白了:

error[E0049]: method `method` has 0 type parameters but its trait declaration has 1 type parameter
 --> src/lib.rs:8:5
  |
2 |     fn method<T>(&self) -> T;
  |     ------------------------- expected 1 type parameter
...
8 |     fn method(&self) -> u8 {
  |     ^^^^^^^^^^^^^^^^^^^^^^ found 0 type parameters

我应该如何正确编写impl 块?

【问题讨论】:

    标签: rust


    【解决方案1】:

    函数和方法中的类型参数是通用的。这意味着对于所有 trait 实现者,Trait::method&lt;T&gt; 必须为任何 T 实现,其约束与 trait 所指示的约束完全相同(在这种情况下,T 上的约束只是隐含的 Sized)。

    您指出的编译器错误消息表明它仍然需要参数类型T。相反,您的Struct 实现假设T = u8,这是不正确的。类型参数由方法的调用者而不是实现者决定,因此T 可能并不总是u8

    如果您希望让实现者选择特定类型,则必须改为在关联类型中具体化。

    trait Trait {
        type Output;
    
        fn method(&self) -> Self::Output;
    }
    
    struct Struct;
    
    impl Trait for Struct {
        type Output = u8;
    
        fn method(&self) -> u8 {
            16
        }
    }
    

    另请阅读Rust 编程语言的这一部分:Specifying placeholder types in trait definitions with associated types

    另见:

    【讨论】:

    • 谢谢,这对我有帮助。我想知道是否可以限制具有特征的类型,例如type Output impl CustomOutput?这就是你所说的泛型关联类型吗?我看到这个 github 的跟踪问题,所以我想知道这是否不可能。
    【解决方案2】:

    除了使用关联类型的方法,从this answer,您还可以将泛型添加到特征中。

    trait Trait<T> {
        fn method(&self) -> T;
    }
    
    impl Trait<u8> for Struct {
        fn method(&self) -> u8 {
            16
        }
    }
    

    当只有一种逻辑形式可供使用时,您使用“关联类型”方式。当有多个有意义的输出类型时,您可以使用通用特征,例如这是合法的:

    struct Struct;
    
    trait Trait<T> {
        fn method(&self) -> T;
    }
    
    impl Trait<u8> for Struct {
        fn method(&self) -> u8 {
            16
        }
    }
    
    impl Trait<String> for Struct {
        fn method(&self) -> String {
            "hello".to_string()
        }
    }
    
    fn main() {
        let s = Struct;
        let a: u8 = s.method();
        let b: String = s.method();
        println!("a={}, b={}", a, b);
    }
    

    据我所知,你不能使用基于关联类型的特征来做到这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-02
      • 2017-10-18
      • 1970-01-01
      • 2023-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多