【问题标题】:What is a concise way to inform the compiler of the specifc type with multiple implementations of a generic trait?什么是通过遗传特征的多个实现通知编译器特定类型的简洁方法?
【发布时间】:2018-01-15 12:25:19
【问题描述】:

我遇到了一个奇怪的类型推理问题,让我有点摸不着头脑。

我正在为多种类型的结构实现通用特征。我从&str开始:

struct Bar<'a> {
    baz: &'a str,
}

trait Foo<T> {
    fn foo(&self) -> T;
}

impl<'a> Foo<&'a str> for Bar<'a> {
    fn foo(&self) -> &'a str {
        self.baz
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_str_a() {
        let bar = Bar { baz: "asd" };
        assert_eq!("asd", bar.foo());
    }
}

这行得通——当我为 u8 类型添加另一个实现时,问题就来了:

struct Bar<'a> {
    baz: &'a str,
}

trait Foo<T> {
    fn foo(&self) -> T;
}

impl<'a> Foo<&'a str> for Bar<'a> {
    fn foo(&self) -> &'a str {
        self.baz
    }
}

impl<'a> Foo<u8> for Bar<'a> {
    fn foo(&self) -> u8 {
        8
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_str_a() {
        let bar = Bar { baz: "asd" };
        assert_eq!("asd", bar.foo());
    }

    #[test]
    fn test_u8() {
        let bar = Bar { baz: "asd" };
        assert_eq!(8 as u8, bar.foo());
    }
}

在这种情况下,我收到以下错误:

error[E0283]: type annotations required: cannot resolve `Bar<'_>: Foo<_>`
  --> src/main.rs:28:31
   |
28 |         assert_eq!("asd", bar.foo());
   |                               ^^^

如果我将值存储在变量中,它会起作用:

let foo: &str = bar.foo();

在我的生产代码中,我做了很多断言,这会使事情变得有点混乱。我也尝试过bar.foo() as &amp;str,但这也失败了,因为编译器也不知道bar.foo() 的类型。我正在尝试为编译器找到一种简洁的方式来了解类型。

【问题讨论】:

    标签: generics types casting rust traits


    【解决方案1】:

    使用 turbofish (::&lt;&gt;) 将类型参数传递给特征:

    assert_eq!("asd", Foo::<&str>::foo(&bar));
    

    您也可以使用fully-qualified syntax 来区分该方法属于哪个特征:

    // This is "type-qualified" and equivalent to `Foo::<&str>::foo(&bar)`
    assert_eq!("asd", <_ as Foo<&str>>::foo(&bar));
    
    // This is "fully qualified"
    assert_eq!("asd", <Bar as Foo<&str>>::foo(&bar));
    

    【讨论】:

    • @Shepmaster,这不是Type的模棱两可的情况。这是一个模棱两可的Trait 的情况,因此不需要完全限定的语法。 Trait::method()&lt;Type as Trait&gt;::method() 的缩写形式。
    • 我不确定我是否在关注您... UFCS 名称不佳,已重命名为 FQS。您最初的回答表明 OP 应该使用 UFCS(因此 FQS),但现在您的评论指出 OP 不应该使用 FQS。
    • 您的第一条评论指出Trait::method() 语法既不是 FQS 也不是 UFCS。我将其视为“FQS 是 &lt;Type as Trait&gt;::method() 语法的特定名称,Trait::method() 语法有其他名称”并相应地回答。
    • 事实上Trait::method()(或Trait::&lt;T1, T2, ... TN&gt;::method())和&lt;Type as Trait&gt;::method()(或&lt;Type as Trait&lt;T1, T2, ... TN&gt;&gt;::method())都是FQS。正如书中所述:“但是,我们可以省略该语法中 Rust 能够从程序中的其他信息中找出的任何部分。”
    • 我声称Trait::method() 不是 FQS,我相信只有带尖括号的表格才是FQS (&lt;Trait&gt;::method / &lt;Type as Trait&gt;::method)。答案中的代码只是使用涡轮鱼来填写类型参数。同样,iterator.collect::&lt;Foo&gt; 没有使用 FQS。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多