【问题标题】:Matching a generic parameter to another generic parameter of an impl将泛型参数与 impl 的另一个泛型参数匹配
【发布时间】:2015-09-04 23:23:46
【问题描述】:

我有这个代码 (in playground):

trait Limit {}

pub trait Trait
{
    fn give<T>(&self, x: T) -> T
    where T: Limit;
}

struct Struct<T: Limit> {field: T}

impl<T> Trait for Struct<T>
    where T: Limit
{   
    fn give<S>(&self, x: S) -> S 
    where S: Limit
    {
       self.field
       //interacts with x parameter and gives an "S: Limit" result       
    }
} 

我想要做的是保留特征Traitgive 函数的签名,同时为通用结构Struct 实现特征Trait

但我收到此错误

<anon>:17:8: 17:14 error: mismatched types:
 expected `S`,
    found `T`
(expected type parameter,
    found a different type parameter) [E0308]
<anon>:17        self.field       
                 ^~~~~~

我想使用我在这个question 中看到的,它将关联参数与通用参数匹配,所以我更改了:

    fn give<S>(&self, x: S) -> S 
    where S: Limit

到:

    fn give<S = T>(&self, x: S) -> S 
    where S: Limit

我没有收到有关此语法的错误,但这不是上述错误的解决方案。

有什么方法可以实现我想做的吗?

还有一个附带问题,&lt;S = T&gt; 在这种情况下实际上做了什么?

【问题讨论】:

    标签: generics rust traits


    【解决方案1】:

    正如您所写,Trait 的实现必须以适用于调用者希望的任何类型的方式实现 give。另一方面,您对Struct&lt;T&gt;give 实现仅适用于特定 类型T

    如何让 trait 本身而不是方法成为通用的?

    pub trait Trait<T> where T: Limit {
        fn give(&self, x: T) -> T;
    }
    
    impl<T> Trait<T> for Struct<T> where T: Limit {   
        fn give(&self, x: T) -> T 
        {
           self.field // does not compile, you can't give away one of your fields
                      // unless you mem::replace() it with another value
        }
    } 
    

    这样,Trait&lt;T&gt; 的实现仅适用于由实现者而不是调用者选择的特定T 类型。

    另一种选择是使用关联类型:

    pub trait Trait {
        type T: Limit;
    
        fn give(&self, x: Self::T) -> Self::T;
    }
    
    impl<T> Trait for Struct<T> where T: Limit {
        type T = T;
    
        fn give(&self, x: T) -> T 
        {
           self.field
        }
    } 
    

    这里,Trait 不再是通用的,但Struct 仍然是通用的,Struct 的每个实例都实现了相同的 Trait 特征。

    【讨论】:

    • 感谢您的回答,是的,这将是一个解决方案,但是实现它会更改 give 函数的签名。老实说,我想要的不是在 trait Trait 上使用泛型,因为这会导致在其他依赖它的 trait 中使用泛型,这是我想要避免的。
    • 最后,在我的情况下,当我定义其他依赖特征时,结合使用您的建议结合将特征Trait 的泛型声明为Self 解决了这个问题。根据Trait 定义其他特征的示例:trait NewTrait: Trait&lt;Self&gt; {...} 但是我会等待另一个解决方案,以防其他人无法在特征定义中使用Self
    • 我添加了另一个解决方案,使用关联类型。
    • 是的,这是一个很好的解决方法,唯一的问题是,如果你要实现 NewTraitTrait 的类型不使用由 Limit 限制的泛型,那么你必须使用 PhantomData 以保持关联的类型是通用的。这个PhantomData 案例与使用Trait&lt;T&gt; 相似,至少在外观上是这样。反正好像没有别的办法了,再多谢你一次的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-26
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    • 2010-12-18
    • 1970-01-01
    相关资源
    最近更新 更多