【问题标题】:"expected type parameter, found struct" when implementing trait实现特征时“预期类型参数,找到结构”
【发布时间】:2016-11-21 04:10:32
【问题描述】:

我正在尝试为有向图结构创建特征并提供一个非常基本的实现,但遇到编译器错误:

pub trait DiGraph<'a> {
    type N;
    fn nodes<T>(&'a self) -> T where T: Iterator<Item=&'a Self::N>;
    fn pre<T>(&'a self, node: Self::N) -> T where T: Iterator<Item=&'a Self::N>;
    fn succ<T>(&'a self, node: Self::N) -> T where T: Iterator<Item=&'a Self::N>;
}

struct SimpleNode {
    pre: Vec<usize>,
    succ: Vec<usize>,
}

pub struct SimpleDiGraph {
    pub nodes: Vec<SimpleNode>
}

impl<'a> DiGraph<'a> for SimpleDiGraph {
    type N = usize;

    fn nodes<T=std::ops::Range<usize>>(&'a self) -> T {
        return std::ops::Range { start: 0, end: self.nodes.len() };
    }
    fn pre<T=std::slice::Iter<'a,usize>>(&'a self, node: usize) -> T {
        return self.nodes[node].pre.iter();
    }
    fn succ<T=std::slice::Iter<'a,usize>>(&'a self, node: usize) -> T {
        return self.nodes[node].succ.iter();
    }
}

错误信息是:

error[E0308]: mismatched types
--> digraph.rs:21:16
|
21 |         return std::ops::Range { start: 0, end: self.nodes.len() };
|                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::ops::Range`
|
= note: expected type `T`
= note:    found type `std::ops::Range<usize>`

error[E0308]: mismatched types
--> digraph.rs:24:16
|
24 |         return self.nodes[node].pre.iter();
|                ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::slice::Iter`
|
= note: expected type `T`
= note:    found type `std::slice::Iter<'_, usize>`

error[E0308]: mismatched types
--> digraph.rs:27:16
|
27 |         return self.nodes[node].succ.iter();
|                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found struct `std::slice::Iter`
|
= note: expected type `T`
= note:    found type `std::slice::Iter<'_, usize>`

错误消息让我有些困惑——为什么类型参数会被期望作为返回值?这仅仅是类型不匹配(例如由于生命周期)并带有误导性错误消息吗?

【问题讨论】:

    标签: rust


    【解决方案1】:

    &lt;T=std::ops::Range&lt;usize&gt;&gt; 不会强制 T 成为 std::ops::Range&lt;usize&gt;,如果它不知道还能使用什么,它只会使其默认为该值。

    如果您只想返回Range&lt;usize&gt;,则使用Range&lt;usize&gt; 作为返回类型;根本没有理由拥有一个通用参数。你的代码现在实际上是这样说的:

    • “你可以选择任何你想要的返回类型!如果你不在乎,我会返回一个range&lt;usize&gt;。”
    • “请您回复String。”
    • “TOUGH你得到了range&lt;usize&gt;!”
    • “……但你说……”
    • “我撒谎了!MUAHAHAHAHA!”

    如果您实际上希望调用者选择返回类型,那么您需要准备返回 any T... 这几乎是不可能的,因为它可以是从 () 到 String 到 OpenGL 渲染上下文的任何内容。

    在这种情况下,您实际上想要做的是将T 限制为需要类型实现某种构造函数的某些特征。 Default 就是一个例子。

    编辑:再次澄清:您无法选择泛型参数中使用的类型,您的调用者会选择。

    直到刚才我才注意到您在特征和实现中使用了不同的定义(不要那样做)。我假设您 真正 想要做的是说“此方法返回 something 可用作 Iterator,但每个 impl 可以选择不同的类型。”你不能用泛型做到这一点。

    你想要是 trait 上的关联类型,如下所示:

    pub trait DiGraph<'a> {
        type Nodes;
        fn nodes(&'a self) -> Self::Nodes;
    }
    
    pub struct SimpleNode {
        pre: Vec<usize>,
        succ: Vec<usize>,
    }
    
    pub struct SimpleDiGraph {
        pub nodes: Vec<SimpleNode>
    }
    
    impl<'a> DiGraph<'a> for SimpleDiGraph {
        type Nodes = std::ops::Range<usize>;
    
        fn nodes(&'a self) -> Self::Nodes {
            return std::ops::Range { start: 0, end: self.nodes.len() };
        }
    }
    

    【讨论】:

    • 谢谢,很好的解释,你猜对了我的意图。但是,在您的情况下,节点可以是任何东西,这意味着在有向图上运行的任何函数都无法做太多事情,因为它无法对节点做出任何假设。所以我想做的是限制节点在 N 上获取迭代器(在我的示例中使用大小,但由调用者定义)。我很高兴 SimpleDiGraph 总是返回 Range 对象,但其他实现有向图的结构应该能够返回 N 上的其他迭代器。有什么方法可以实现吗?
    • 我想我明白了,似乎你实际上可以限制特征类型,例如 type NodeIterator: Iterator; 应该这样做诀窍。现在只是为了弄清楚生命周期的问题。
    猜你喜欢
    • 2014-11-20
    • 1970-01-01
    • 2022-01-20
    • 2018-04-11
    • 2022-11-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    相关资源
    最近更新 更多