Rust无法在没有注释的情况下推断类型

4
下面的代码由于类型错误无法编译:error[E0283]: type annotations required: cannot resolve _: std::cmp::Eq。为了编译此代码需要什么类型注释?
这个例子代码来自一个更大的程序,其中MyHashGenerator::hash_node()用于哈希AST中的节点(类型T与AST节点内保存的值相关,但不需要重现此类型错误时的AST定义)。
use std::hash::Hash;

pub trait HashGenerator<T: Clone + Eq + Hash + ToString> {
    fn hash(&self, msg: &str) -> u64;  // Hash a string.
    fn hash_node(&self) -> u64;  // Hash an AST node.
}

struct MyHashGenerator {}

impl<T: Clone + Eq + Hash + ToString> HashGenerator<T> for MyHashGenerator {
    fn hash(&self, msg: &str) -> u64 {
        0
    }

    fn hash_node(&self) -> u64 {
        // error[E0283]: type annotations required: cannot resolve `_: std::cmp::Eq`
        self.hash("")
    }
}

在Playground上查看代码。

这个问题类似于这里的问题,但没有得到解答。


正确。但是为MyHashGenerator实现Eq并不能解决错误。 - snim2
1个回答

8
问题在于MyHashGenerator没有使用类型参数。所以你做了一个承诺,“相同的类型MyHashGenerator将作为哈希生成器,并且无论T如何,它的行为都将完全相同”。self.hash("")是对HashGeneratorhash调用,但是 Rust 并不一定知道它是 hash_node 调用的相同HashGenerator实例。你可以通过以下两种方式之一使这个要求变得明确。 选项1:显式类型参数 通过显式地告诉 Rust 参数是什么,你可以避免这个问题。
fn hash_node(&self) -> u64 {
    HashGenerator::<T>::hash(self, "")
}

现在它知道要调用特定的<T>实例,这就足够了。

选项2:虚拟数据

您可以将MyHashGenerator参数化以具有(未使用的)T参数。

use std::marker::PhantomData

...

struct MyHashGenerator<T> {
    foo: PhantomData<T>
}

接着,Rust可以根据self的类型推断出你想要的实例,只要你将实例声明为:

impl<T: Clone + Eq + Hash + ToString> HashGenerator<T> for MyHashGenerator<T> {
    ...
}

那么您就不需要更改hash_size的实现。

个人建议选择选项1。虽然不太美观,但它提供了额外的API保证,无论T如何,事情都将以相同的方式工作。但是,如果您认为MyHashGenerator可能稍后使用T参数(或者如果它现在使用,只是没有包含在您的MCVE中),则可以考虑选择选项2,以使该依赖关系更加清晰。


1
谢谢,这很有道理。我错过它的原因是在原始代码中,self.hash被传递了一个函数调用,该函数本身接受一个参数,该参数是基于T参数化的。我想这就是生活吧! - snim2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接