Факторизовать методы, используя & Box <T>и & T в качестве аргумента - PullRequest
0 голосов
/ 01 марта 2019

У меня есть метод, который мне нужно вызвать с параметром trait (давайте назовем его Listener).Причина в том, что иногда я ранее сохранял этот параметр черты в родительской структуре, поэтому он находится внутри Box, а иногда нет.

Поэтому у меня есть два метода:

  • fref<T>(t: &T) where T: Listener
  • fbox(t: &Box<dyn Listener>)

и я бы хотел, чтобы они оба позвонили f(t: ??).На данный момент я продублировал код в fref и fbox, который работает, но не хорошо.Поэтому я ищу сигнатуру f, из-за которой fref и fbox могли бы вызывать факторизацию моего кода.Я надеялся, что одна из черт, реализованных в Box, будет эквивалентна & (или, по крайней мере, где-нибудь найдет общий язык).

Я попробовал следующее:

  • Запись f<T>(t: &T) where T: Listener, но тогда я не могу позвонить с fbox (Listener не реализовано Box<dyn Listener>).
  • Затем измените вызов из fbox на f(&*t), чтобы распаковать мой Box<Listener>, но, поскольку t не Size d, я не могу.

  • Запись f<T>(t: &T) where T: std::borrow::Borrow<Listener>, но тогда я не могу позвонить с fref (Borrow не реализовано Listener)

  • То же самое с AsRef<Listener>
  • Последняя попытка с Deref детской площадкой :
trait Listener {}
struct Mouse {}
impl Listener for Mouse {}

fn fbox(t: &Box<Listener>) {
    f(t);
}

fn fref<T>(t: &T)
where
    T: Listener,
{
    f(t);
}

fn f<T>(_t: &T)
where
    T: std::ops::Deref<Target = Listener>,
{

}

fn create_listener() -> impl Listener {
    Mouse {}
}

fn main() {
    let mouse = create_listener();
    let box_mouse: Box<Listener> = Box::new(Mouse {});

    fref(&mouse);
    fbox(&box_mouse);
}

1 Ответ

0 голосов
/ 02 марта 2019

Listener - это признак, поэтому Box<Listener> - это на самом деле - объект признака, Box<dyn Listener> - к сожалению, ключевое слово dyn в настоящее время является необязательным.И Box<dyn Listener>, и &Mouse реализуют Deref со связанным типом Target, который реализует Listener.В случае &Mouse значение deref Target равно Mouse, но в случае Box<dyn Listener> это неизвестный объект dyn Listener размера неизвестного .

Чтобы собрать всю эту информацию, вы можете написать f следующим образом:

fn f<T, L>(_listener: &T)
where
    T: Deref<Target = L>,
    L: Listener + ?Sized
{
}

И вызывать ее из каждой функции следующим образом:

fn fbox(listener: &Box<dyn Listener>) {
    f(listener);
}

fn fref<L>(listener: &L)
where
    L: Listener
{
    f(&listener);
}

Другой, возможно, более простой способ взглянуть на это - отказаться от ограничения Deref и просто использовать обычные ссылки.Используйте Box::as_ref, чтобы превратить Box в ссылку, чтобы вызвать ее.Неограниченное ограничение ?Sized все еще необходимо для случая объекта черты, и все еще работает, так как значение всегда находится за указателем:

fn fbox(listener: &Box<dyn Listener>) {
    f(listener.as_ref());
}

fn fref<L>(listener: &L) where L: Listener {
    f(listener);
}

fn f<L>(_listener: &L)
where
    L: Listener + ?Sized
{
}
...