2016-12-14 54 views
2

我有一个特征定义了一个可以保存值的对象的接口。性状具有获取当前值的方式:如何通过引用抽象为值或值本身?

pub trait HasValue<T> { 
    fn get_current_value(&self) -> &T; 
} 

这是好的,但我意识到,这取决于实际应用中,有时是方便,如果T存储在现场返回的引用,有时它是如果后台字段正在跨线程共享(例如),则方便返回T的克隆。我正在努力弄清楚如何在特征中表现这一点。我能有这样的事情:

pub enum BorrowedOrOwned<'a, T: 'a> { 
    Borrowed(&'a T), 
    Owned(T) 
} 

impl<'a, T: 'a> Deref for BorrowedOrOwned<'a, T> { 
    type Target = T; 

    fn deref(&self) -> &T { 
     use self::BorrowedOrOwned::*; 

     match self { 
      &Borrowed(b) => b, 
      &Owned(ref o) => o, 
     } 
    } 
} 

,并更改get_current_value()返回一个BorrowedOrOwned<T>,但我不知道这是地道的。 BorrowedOrOwned<T>有点让我想起Cow<T>,但由于Cow的点是写上复制而我将放弃任何写入,这似乎语义错误。

Cow<T>抽象通过引用或拥有的值的正确方法?有没有比BorrowedOrOwned<T>更好的方法?

+0

会返回一个关联的类型'B:借用'工作吗? –

+0

@ChrisEmerson我不确定这样做的折衷是什么,所以我不确定。你可以扩展一下吗?这似乎是一个普遍有用的问题,所以即使他们没有解决我的具体情况,我也会对所有答案感兴趣。 –

+0

我觉得其实并没有直接帮助。你最终还是需要像牛这样的东西。 –

回答

7

我建议您使用Cow,因为您的BorrowedOrOwnedCow没有区别,只是它具有较少的便利方法。任何持有BorrowedOrOwned对象的人都可以匹配它并获取拥有的值或可变引用。如果您想防止能够获取可变引用或对象本身的混淆,下面的解决方案也适用。

对于您的使用案例,我只需保留&T,因为没有理由让API更复杂。如果用户想要usize,则当Tusize时,他们可以简单地解引用参考。

如果您希望用户以自己的方式实际处理它,则拥有的对象才有意义。即使如此,Cow的目的是为了不要求任何人clone它通过所有权通过的大/重物体的抽象。您的使用案例正好相反,您想通过所有权传递小对象以防止用户需要复制小对象,而是复制它。

+0

感谢您的建议。在简化问题时,我错误地陈述了我有时想要返回'&T'的原因以及其他需要返回'T'的原因。如果实现在'Arc >(例如)中存储'T',那么不可能简单地返回'&T'。必须克隆'T',并且由于克隆驻留在函数的堆栈上,所以不能返回对其的引用。我希望这有帮助。 PS。在RBR与你谈话:) –

+1

啊!这更有意义。那么..然后,我建议你的'BorrowedOrOwned'应该是'enum借入<'a, T> {Ref(&'a T),Arc(Arc >),Rc(Rc >)}'或者沿着这些线。它由'RefCell'变得复杂,因为许多用例可能不需要'RefCell',但是如果不了解更多关于用例的信息,我想这可以解决它。 –

+0

非常真实。我将不得不一直使用它,但是我会将它标记为答案,因为你已经回答了关于“牛”的问题,这已经明确指出了我的正确方向。谢谢 –