2015-08-26 2 views
3

У меня есть сторонние библиотеки с кодом вроде этого:Как реализовать FnMut, который возвращает ссылку с параметром lifetime?

pub struct Foo<T> { t: T } 

impl<'a, T> Foo<T> where T: 'a + FnMut() -> &'a [u8] { 
    pub fn from_callback(closure: T) -> Self { 
     Foo { t: closure } 
    } 
} 

Он прекрасно работает с закрытием:

let buffer = vec![0; 100]; 
Foo::from_callback(move || &buffer) 

однако я хочу, чтобы вернуться Foo из моей функции. Из-за этого я не могу использовать закрытие, поэтому я решил использовать собственную структуру, которая реализует FnMut.

Я определил структура:

pub struct Func { 
    buffer: Vec<u8>, 
} 

затем реализован FnMut для него:

#![feature(unboxed_closures)] 

impl FnMut<()> for Func { 
    extern "rust-call" fn call_mut(&mut self, _:()) -> Self::Output { 
    &self.buffer 
    } 
} 

реализации FnOnce затем требуется:

impl FnOnce<()> for Func { 
    type Output = &[u8]; 
       ^~~~ error: missing lifetime specifier [E0106] 
    extern "rust-call" fn call_once(self, _:()) -> Self::Output { 
    unimplemented!(); 
    } 
} 

Но я не знаю, что используйте как время жизни для справки в Output.

+0

Буду рад, если кто-то мне противоречит, однако я боюсь, что это то, что потребует HKT (более высокие категории). –

ответ

1

@MatthieuM. верно. Это невозможно сделать без более высоких типов, и даже если бы они были доступны, я не совсем уверен, что для поддержки его можно было бы изменить свойства Fn*.

Проблема в том, что вы хотите, чтобы ваша функция возвращала срез вектора внутри этой функции. Однако, это потребует call_mut() иметь следующую подпись:

fn call_mut<'a>(&'a mut self, _:()) -> Self::Output<'a> 

Параметр времени жизни является обязательным, потому что это единственный способ указать, что результат вызова функции будет жить ровно до тех пор, как сама функция. Это, в свою очередь, требует Output соответствующего типа иметь пожизненную аргумент:

trait FnOnce<A> { 
    type Output<'a>; 
    ... 
} 

Это именно то, что HKT позволит. Однако я не уверен, что можно использовать HKT для функций. Помните, что каждый FnMut также является FnOnce: если у вас есть функция, которая может быть вызвана несколько раз, тогда ее также можно вызвать один раз. Естественно, результаты FnMut и FnOnce должны быть эквивалентными. Однако нет способа вернуть заемные данные от FnOnce, так как он принимает функцию по значению. В вашем случае вектор будет перемещен в функцию, и, поскольку функция возвращает срез, а не вектор, ему некуда идти, и поэтому он будет уничтожен. Поэтому для такого изменения потребуется, чтобы некоторые функции были FnMut/Fn, но не FnOnce; Я не уверен, что это желательно или даже возможно.

+0

Нельзя ли утверждать, что каждое использование распакованного закрытия может быть освобождено в struct, реализующее 'Fn (Once | Mut |)'? – kriomant

+0

Это правда, но как это связано с вашим вопросом? –

+0

О, теперь я понимаю, что вы имеете в виду. Я не знаю, почему в этом случае работают затворники. Unboxed закрытия имеют глубокую поддержку в компиляторе, так что, возможно, это часть магии компилятора. Во всяком случае, ручная реализация черт «Fn» включена в функции, поэтому такие проблемы не являются неожиданными. –

Смежные вопросы