Время жизни связанного типа при передаче внутренней ссылки на обобщенное замыкание - PullRequest
0 голосов
/ 28 октября 2018

Вот пример, который прекрасно компилируется:

use std::cell::RefCell;
use std::rc::Rc;

struct Foo<'a> {
    val: Rc<RefCell<i32>>,
    dummy: Option<&'a i32>,
}

fn consume<T>(_: T) {}

impl<'a> Foo<'a> {
    // Note that &i32 has no lifetime markers
    fn subscribe<F>(self, func: F)
    where
        F: Fn(&i32) + 'a,
    {
        let val = self.val.clone();
        consume(move |x: i32| {
            *val.borrow_mut() = x;
            func(&*val.borrow())
        })
    }
}

Вот то, чего я пытаюсь достичь и не компилирую:

use std::cell::RefCell;
use std::rc::Rc;

trait Stream<'a> {
    type Item: 'a;

    fn subscribe<F>(self, func: F)
    where
        F: Fn(Self::Item) + 'a;
}

struct Bar<'a, S: Stream<'a>> {
    stream: S,
    val: Rc<RefCell<S::Item>>,
}

impl<'a, S: Stream<'a>> Stream<'a> for Bar<'a, S> {
    type Item = &'a S::Item; // 'a doesn't seem right here...

    fn subscribe<F>(self, func: F)
    where
        F: Fn(Self::Item) + 'a,
    {
        let val = self.val.clone();
        self.stream.subscribe(move |x: S::Item| {
            *val.borrow_mut() = x;
            func(&*val.borrow());
        })
    }
}

Этот пример почти идентиченпервый.Единственное отличие состоит в том, что, поскольку это признак, мы должны назначить явное время жизни для ассоциированного типа, Item, который является ссылкой.Установка его на 'a вызывает конфликты времени жизни (справедливо):

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> src/lib.rs:27:24
   |
27 |             func(&*val.borrow());
   |                        ^^^^^^
   |
note: first, the lifetime cannot outlive the lifetime  as defined on the body at 25:31...
  --> src/lib.rs:25:31
   |
25 |         self.stream.subscribe(move |x: S::Item| {
   |                               ^^^^^^^^^^^^^^^^^
note: ...so that closure can access `val`
  --> src/lib.rs:27:20
   |
27 |             func(&*val.borrow());
   |                    ^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 17:6...
  --> src/lib.rs:17:6
   |
17 | impl<'a, S: Stream<'a>> Stream<'a> for Bar<'a, S> {
   |      ^^
note: ...so that reference does not outlive borrowed content
  --> src/lib.rs:27:18
   |
27 |             func(&*val.borrow());
   |                  ^^^^^^^^^^^^^^

Фактически, первый пример может быть изменен так, чтобы он завершился с ошибкой с той же самой ошибкой, если вы заменили Fn(&i32) на Fn(&'a i32) в сигнатуре функции.

Можно ли скомпилировать второй пример?Возможно, с помощью некоторых хаков или небезопасных блоков, я был бы готов принять что-нибудь действительно.Изменение подписи или перестановка логики, если это требуется.Каким должен быть срок службы ассоциированного типа Item?

1 Ответ

0 голосов
/ 28 октября 2018

Первый пример можно скомпилировать, указав, что F должен иметь возможность иметь дело с более общими временами жизни:

impl<'a> Foo<'a> {
    fn subscribe<F>(self, func: F)
    where
        for<'b> F: Fn(&'b i32) + 'a, // f can cope with any lifetime 'b
    {
        let val = self.val.clone();
        consume(move |x| {
            *val.borrow_mut() = x;
            func(&*val.borrow())
        })
    }
}

Насколько я вижу, ваш второй пример страдает как минимум от одногоДругая проблема: Вы вызываете

self.stream.subscribe(move |x: S::Item| {
    *val.borrow_mut() = x;
    func(&*val.borrow());
})

, но subscribe принимает функцию, принимающую заем (т.е. &S::Item, а не S::Item).Если вы передадите ссылку, я не уверен, если / как вы можете присвоить это val.borrow_mut.Возможно, вам придется преобразовать его в собственное значение.

Как вы уже упоминали, вы также можете установить Item = S::Item (без заимствования).Это, однако, означает, что вы не можете просто передать val.borrow() в func в закрытии, так как это переместится из заемного значения.Опять же, решение может заключаться в том, чтобы как-то преобразовать его в собственное значение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...