Как express ограничения времени жизни замыкания, чтобы соответствовать ограниченному времени жизни черты? - PullRequest
1 голос
/ 13 апреля 2020

У меня есть черта, которая возвращает заем, привязанный к его собственному времени жизни:

trait SomeTrait {
    fn do<'a>(&'a self, other: &AnonymousLifetime) -> &'a Output;
}

Как это же ограничение может быть выражено в выражении для замыкания, так что SomeTrait can impl From<Closure>?

Пример

A минимальный, воспроизводимый пример для сценария ( детская площадка ):

// The traits
trait Context {
    fn give(&self) -> usize;
}
trait ContextDecider {
    fn decide<'a>(&'a self, context: &dyn Context) -> &'a str;
}

// A concrete implementation example
// As expected, works OK
struct SomeDecider(Vec<String>);
impl ContextDecider for SomeDecider {
    fn decide<'a>(&'a self, context: &dyn Context) -> &'a str {
        let some_context = context.give();
        if some_context > self.0.len() {
            panic!("Oh no!");
        }

        &self.0[some_context]
    }
}

// An implemetation for a closure
// Help here!!
impl<'a, F> ContextDecider for F
where
    F: 'a + Fn(&dyn Context) -> &'a str,
{
    fn decide<'b>(&'b self, giver: &dyn Context) -> &'b str {
        self(giver)
    }
}

Не удается скомпилировать:

error[E0312]: lifetime of reference outlives lifetime of borrowed content...
  --> src/lib.rs:30:9
   |
30 |         self(giver)
   |         ^^^^^^^^^^^
   |
note: ...the reference is valid for the lifetime `'b` as defined on the method body at 29:15...
  --> src/lib.rs:29:15
   |
29 |     fn decide<'b>(&'b self, giver: &dyn Context) -> &'b str {
   |               ^^
note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the impl at 25:6
  --> src/lib.rs:25:6
   |
25 | impl<'a, F> ContextDecider for F
   |      ^^

В этом примере мне не удается express в закрытии ограничивает ограничение, накладываемое признаком, и компилятор не удовлетворен.
Компилятор не помогая мне с тем, какой синтаксис мне следует использовать, что позволит мне соединить две жизни вместе.

Ответы [ 2 ]

2 голосов
/ 14 апреля 2020

Можете ли вы применить пожизненную черту, привязанную к ContextDecider? (Так что вы получите ContextDecider <'a> instead of having the lifetime only on решить`.)

Это приведет к следующему:

trait Context {
    fn give(&self) -> usize;
}
trait ContextDecider<'a> {
    fn decide(&'a self, context: &dyn Context) -> &'a str;
}

struct SomeDecider(Vec<String>);
impl<'a> ContextDecider<'a> for SomeDecider {
    fn decide(&'a self, context: &dyn Context) -> &'a str {
        let some_context = context.give();
        if some_context > self.0.len() {
            panic!("Oh no!");
        }

        &self.0[some_context]
    }
}

impl<'f, F> ContextDecider<'f> for F
where
    F: 'f,
    for<'ctx>F: Fn(&'ctx dyn Context) -> &'f str,
{
    fn decide(&'f self, giver: &dyn Context) -> &'f str {
        self(giver)
    }
}
1 голос
/ 17 апреля 2020

Вы можете заключить функцию в другую структуру (здесь она называется FnWrapper):

trait Context {
    fn give(&self) -> usize;
}
impl Context for () {
    fn give(&self) -> usize {0}
}
trait ContextDecider {
    fn decide<'a>(&'a self, context: &dyn Context) -> &'a str;
}

struct SomeDecider(Vec<String>);
impl ContextDecider for SomeDecider {
    fn decide<'a>(&'a self, context: &dyn Context) -> &'a str {
        let some_context = context.give();
        if some_context > self.0.len() {
            panic!("Oh no!");
        }

        &self.0[some_context]
    }
}

struct FnWrapper<'a, F> {
    f: F,
    _phantom: std::marker::PhantomData<& 'a ()>,
}
impl<'a, F> FnWrapper<'a, F> 
    where F: 'a + Fn(&dyn Context) -> &'a str,
{
    fn new(f: F) -> Self {
        Self {
            f,
            _phantom: Default::default(),
        }
    }
    fn f_decide<'b>(&'b self, giver: &dyn Context) -> &'b str {
        (self.f)(giver)
    }
}

impl<'a, F> ContextDecider for FnWrapper<'a, F>
where
    F: 'a + Fn(&dyn Context) -> &'a str,
{
    fn decide<'b>(&'b self, giver: &dyn Context) -> &'b str {
        self.f_decide(giver)
    }
}

fn main() {
    println!("{}", FnWrapper::new(|giver| vec!["1", "2", "3"][giver.give()]).decide(&()));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...