我正在尝试编写一个可以下降到任何类型的Value
的函数,并告知Delegate
它所观察到的相似之处。我们的想法是通过各种Json / Yaml / YouNameIt值来完成这项工作。
这是一个触发问题的MVCE(playground link):
pub trait Value: PartialEq<Self> {
type Item;
type Key;
fn items<'a>(&'a self) -> Option<Box<Iterator<Item = (Self::Key, &'a Self::Item)> + 'a>>;
}
pub trait Delegate<'a, V> {
fn something(&mut self, _v: &'a V) {}
}
pub fn diff<'a, V, D>(l: &'a V, d: &'a mut D)
where V: Value,
<V as Value>::Item: Value,
D: Delegate<'a, V>
{
d.something(l);
let v = l.items().unwrap().next().unwrap();
d.something(v.1);
}
struct Recorder;
impl<'a, V> Delegate<'a, V> for Recorder {}
#[derive(PartialEq)]
struct RecursiveValue;
impl Value for RecursiveValue {
type Key = usize;
type Item = RecursiveValue;
fn items<'a>(&'a self) -> Option<Box<Iterator<Item = (Self::Key, &'a Self::Item)> + 'a>> {
None
}
}
fn main() {
let v = RecursiveValue;
let mut r = Recorder;
diff(&v, &mut r);
}
尝试编译代码时,会产生以下错误:
error[E0308]: mismatched types
--> <anon>:19:17
|
19 | d.something(v.1);
| ^^^ expected type parameter, found associated type
|
= note: expected type `&'a V`
= note: found type `&<V as Value>::Item`
我试图说相关的Item
类型也属于V
类型。有没有办法让这种算法一般工作?
答案 0 :(得分:2)
答案在于Rust书的Associated Types章的最底层。
在绑定中使用泛型类型时,如V: Value
中所述,可以使用Generic<AssociatedType = SpecificType>
语法将一个或多个关联类型约束为特定类型。
在您的情况下,这意味着将V
限制为Value<Item = V>
。这也应该淘汰任何进一步限制V::Item
的理由,因为V
的界限是自然可用的。
我鼓励你阅读这本书,以帮助你学习Rust,或者至少浏览它以了解那里有什么,并且当你遇到困难时可以参考它。
答案 1 :(得分:1)
这是一个进一步缩小的例子:
pub trait Value {
type Item;
fn items(&self) -> &Self::Item;
}
pub trait Delegate<V> {
fn something(&mut self, v: &V);
}
pub fn diff<V, D>(l: &V, d: &mut D)
where V: Value,
V::Item: Value,
D: Delegate<V>
{
let v = l.items();
d.something(v);
}
fn main() {}
要关注的重点是对diff
:
pub fn diff<V, D>(l: &V, d: &mut D)
where V: Value,
V::Item: Value,
D: Delegate<V>
用语言来说,这说:
V
可以是任何类型,只要它实现Value
特征。V::Item
可以是任何类型,只要它实现Value
特征。D
可以是任何类型,只要它实现Delegate<V>
特征。列出的要求列表中没有任何地方&#34; V
和V::Item
必须相同&#34;。事实上,它是一个功能,它们不需要是相同的。
在此缩减中,另一种解决方案是D: Delegate<V::Item>
。但是,这不适用于稍大的再现:
pub fn diff<V, D>(l: &V, d: &mut D)
where V: Value,
V::Item: Value,
D: Delegate<V::Item>
{
d.something(l);
let v = l.items();
d.something(v);
}
作为Matthieu M. has pointed out,您要指定特征的关联类型:
pub fn diff<V, D>(l: &V, d: &mut D)
where V: Value<Item = V>,
D: Delegate<V>
如需进一步阅读,请查看Requiring implementation of Mul in generic function。