Фон
Затворы в 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 ()>,
}