2016-12-14 3 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 составляет copy-on-write, и я буду отбрасывать любые записи, которые кажутся семантически неправильными.

Действительно ли Cow<T> правильный способ аннотация над ссылкой или стоимостью? Есть ли лучший способ, чем BorrowedOrOwned<T>?

+0

Вернул бы связанный тип 'B: Borrow ' работа? –

+0

@ChrisEmerson Я не уверен, какие компромиссы в этом будут, поэтому я не уверен. Не могли бы вы немного рассказать об этом? Это похоже на вопрос, который может быть в целом полезен, поэтому меня интересуют все ответы, даже если они не затрагивают мою конкретную ситуацию. –

+0

Я думаю, что на самом деле это не помогает напрямую; вы все еще нуждаетесь в чем-то вроде «Корова». –

ответ

7

Я предлагаю вам использовать Cow, так как ваш BorrowedOrOwned не имеет значения для Cow, за исключением того, что у него меньше удобных методов. Любой, у кого есть объект BorrowedOrOwned, может совпадать с ним и получить принадлежащее ему значение или измененную ссылку на него. Если вы хотите предотвратить путаницу в возможности получить изменчивую ссылку или сам объект, то также применяется нижеприведенное решение.

Для вашего случая использования я просто останусь с &T, так как нет причин для того, чтобы сделать API более сложным. Если пользователю нужен usize, когда T - usize, они могут просто разыменовать ссылку.

Собственный объект имеет смысл только в том случае, если вы ожидаете, что пользователь фактически обработает его собственными способами. И даже тогда, Cow предназначен для абстрагирования над большими/тяжелыми объектами, которые вы проходите по собственному желанию, чтобы не требовать никого до clone. Ваш вариант использования - это наоборот, вы хотите передать небольшие объекты по собственному усмотрению, чтобы пользователи не могли копировать небольшие объекты, а вместо этого вы их копируете.

+0

Спасибо за совет. В упрощении проблемы я исказил свои причины, порой желая вернуть '& T' и другие времена, требующие вернуть' T'. Если реализация хранит 'T' в' Arc > '(например), тогда невозможно просто вернуть' & T'. 'T' должен быть клонирован, и поскольку клон живет в стеке функции, вы не можете вернуть ссылку на него. Надеюсь, это полезно. PS. Было здорово разговаривать с вами в RBR :) –

+1

А! Это имеет больше смысла. Ну .. Я тогда предлагаю, чтобы ваш 'BorrowedOrOwned' должен быть' enum Borrow <'a, T> {Ref (& 'a T), Arc (Arc >), Rc (Rc >)} 'или что-то в этом роде.Это осложняется «RefCell», поскольку многие варианты использования могут не хотеть «RefCell» там, но, не зная больше о прецеденте, я бы предположил, что это решило бы. –

+0

Очень верно. Мне придется немного поиграть с этим, но я собираюсь отметить это как ответ, так как вы ответили на мой вопрос о 'Cow', и это определенно указало мне в правильном направлении. Спасибо –

Смежные вопросы