如何仅在从同一父对象创建对象时才比较对象?

mon*_*och 6 rust

我想Obj只在它们是从同一个Parent对象创建时进行比较,并且它可以工作,但只有一种方法:如果你切换比较顺序,它就不会.

这是最小的代码:

use std::marker::PhantomData;

struct Parent {
    val: u64,
}

impl Parent {
    pub fn new(v: u64) -> Parent {
        Parent { val: v }
    }

    pub fn child(&self, v: u64) -> Child {
        Child {
            val: v,
            phantom: PhantomData,
        }
    }
}

struct Child<'a> {
    val: u64,
    phantom: PhantomData<&'a Parent>,
}

impl<'a> Child<'a> {
    pub fn compare(&'a self, l: &Obj<'a>, r: &Obj<'a>) -> bool {
        l.val == r.val
    }

    pub fn obj(&'a self, v: u64) -> Obj<'a> {
        Obj {
            val: v,
            child: self,
        }
    }
}

struct Obj<'a> {
    val: u64,
    child: &'a Child<'a>,
}

impl<'a> PartialEq<Obj<'a>> for Obj<'a> {
    fn eq(&self, other: &Obj<'a>) -> bool {
        self.child.compare(self, other)
    }
}

#[test]
fn test() {
    let parent = Parent::new(1);
    let child = parent.child(2);
    let obj1 = child.obj(3);
    let obj2 = child.obj(3);

    // those are from the same parent, this sould work (and works).
    assert!(obj1 == obj2);
    assert!(obj2 == obj1);

    let parent2 = Parent::new(1);
    let child2 = parent2.child(2);
    let obj12 = child2.obj(3);
    let obj22 = child2.obj(3);

    // this works fine too
    assert!(obj12 == obj22);
    assert!(obj22 == obj12);

    // those are from different parents

    //assert!(obj1 == obj12); // that line DOES NOT compile, which is exactly what I want!
    assert!(obj12 == obj1); // but that line suddenly DOES compile.
}
Run Code Online (Sandbox Code Playgroud)

如何更改代码以便最后一行不会编译?

blu*_*uss 3

我很乐意解释生命周期方法,但它似乎并不可行。

什么时候是(表示为)X的子类型?YX <: Y

对仿制药提出的问题涉及方差

方差回答了这个问题:对于泛型类型, to的关系意味着G<X>什么。X <: YG<X>G<Y>

  • 协方差:X <: Y=>G<X> <: G<Y>
  • 不变性:X == Y=>G<X> <: G<Y>
  • 逆变:X <: Y=>G<Y> <: G<X>

Cell<X>是不变的 wrt X,因此phantom: PhantomData<Cell<&'a Parent>>,使得Child<'a> 不变的wrt 'a

PhantomData是一种通过仅用您已经知道的类型来描述方差来欺骗您谈论方差的方法。

这似乎有效,但不是那么快,因为我们可以创建一种生命周期完全相等的情况,然后测试再次编译!

let (parent, parent2) = (Parent::new(1), Parent::new(1));
let (child, child2) = (parent.child(2), parent2.child(2));
// Plan is foiled!!
Run Code Online (Sandbox Code Playgroud)