Как указать общее время жизни для параметров указателя функции? - PullRequest
0 голосов
/ 04 июня 2018

Фон

Затворы в Rust имеют анонимный тип и не могут называться известным конкретным типом.Однако с февраля 2017 года , все неперехватывающие замыкания могут быть преобразованы в анонимные функции и иметь тот же тип, что и указатель на функцию.

Я хотел создать тип, который стандартизирует каррированные замыкания.Если у нас есть функция fn(T1, T2, ...) -> R, у нас может быть специальный тип FnXXX(T2, ...) -> R (замените XXX на или Mut или Once, или Box).Затем их можно использовать внутри контейнеров без использования динамической отправки.

Попытка для FnOnce

Следующие работы:

#![feature(unboxed_closures)]
#![feature(fn_traits)]

struct Curry0<T, R> {
    f: fn(T) -> R,
    v: T,
}
impl<T, R> FnOnce<()> for Curry0<T, R> {
    type Output = R;
    extern "rust-call" fn call_once(self, _: ()) -> R {
        (self.f)(self.v)
    }
}

fn curry<T, R>(f: fn(T) -> R, v: T) -> impl FnOnce() -> R {
    Curry0 { f: f, v: v }
}

fn main() {
    curry(|s| println!("{}", s), "Hello, World!")()
}

Однако,Я не могу добавить следующее:

impl<'a, T, R> FnMut<()> for Curry0<&'a mut T, R> {
    extern "rust-call" fn call_mut(&mut self, _: ()) -> R {
        (self.f)(self.v)
    }
}

Сообщение об ошибке:

error[E0312]: lifetime of reference outlives lifetime of borrowed content...
  --> src/main.rs:16:18
   |
16 |         (self.f)(self.v)
   |                  ^^^^^^
   |
note: ...the reference is valid for the lifetime 'a as defined on the impl at 14:1...
  --> src/main.rs:14:1
   |
14 | impl<'a, T, R> FnMut<()> for Curry0<&'a mut T, R> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 15:5
  --> src/main.rs:15:5
   |
15 | /     extern "rust-call" fn call_mut(&mut self, _: ()) -> R {
16 | |         (self.f)(self.v)
17 | |     }
   | |_____^

Насколько я понимаю, call_mut должно позаботиться о том, чтобы &mut selfтолько для самой функции, и поэтому, если f возвращает что-то, что относится к v внутри, оно будет недействительным.

Попытка для FnMut

Чтобы работать с FnMut вместо FnOnce выше, я написал:

#![feature(unboxed_closures)]
#![feature(fn_traits)]

struct Curry0Mut<'a, 'b, T, R>
where
    T: 'a,
    R: 'b,
{
    f: fn(&mut T) -> R,
    v: &'a mut T,
    _l: std::marker::PhantomData<&'b ()>,
}
impl<'a, 'b, T, R> FnOnce<()> for Curry0Mut<'a, 'b, T, R> {
    type Output = R;
    extern "rust-call" fn call_once(self, _: ()) -> R {
        (self.f)(self.v)
    }
}
impl<'a, 'b, T, R> FnMut<()> for Curry0Mut<'a, 'b, T, R>
where
    T: 'a,
    R: 'b,
{
    extern "rust-call" fn call_mut(&mut self, _: ()) -> R {
        (self.f)(self.v)
    }
}

fn curry<'a, T, R>(f: fn(&mut T) -> R, v: &'a mut T) -> impl FnMut() -> R + 'a {
    Curry0Mut {
        f: f,
        v: v,
        _l: std::marker::PhantomData,
    }
}

fn main() {
    let mut v = "Hello, World".to_owned();
    curry(|s| println!("{}", s), &mut v)();
}

Это более сложно, и, к сожалению, у нас есть две структуры для немного отличающегося использования.Когда я посмотрел поближе на изменение, которое я должен сделать здесь, я обнаружил, что f на самом деле является универсальной функцией для времени жизни ее параметра, и время жизни T не зависит от этого.Мы также должны убедиться, что R не живет дольше, чем само замыкание, поэтому его время жизни должно быть закодировано внутри замыкания.

Я не буду вдаваться в подробности для Fn, поскольку оно похоже.Только чтобы заметить, что это усугубляет ситуацию, поскольку нам нужен еще один вариант Curry0, поскольку &mut T не &T.

Вопрос

ЭтоМожно выразить тот факт, что v имеет ожидаемое время жизни, отличное от f s параметра?

Например, как написать что-то вроде:

struct Curry0<'a, 'b, T, R>
where
    R: 'b,
{
    f: fn(T) -> R, //T have generic lifetime
    v: T,          //T: 'a
    _a: std::marker::PhantomData<&'a ()>,
    _b: std::marker::PhantomData<&'b ()>,
}
...