如何实现返回带有生命周期参数的引用的FnMut?

时间:2015-08-26 06:52:38

标签: rust

我有第三方库,代码如下:

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

我已经定义了struct:

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中作为生命周期使用什么作为参考。

2 个答案:

答案 0 :(得分:1)

@MatthieuM。是正确的。如果没有更高级别的类型,这是不可能做到的,即使它们可用,我也不能完全确定Fn*特征可以改变以支持它。

问题是,你希望你的函数在这个函数中返回一个向量切片。但是,这需要call_mut()具有以下签名:

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

lifetime参数是必需的,因为它是指定函数调用的结果与函数本身一样长的唯一方法。这反过来要求Output关联类型具有生命周期参数:

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

这正是香港电讯所允许的。但是,我不确定是否可以将HKT用于功能。请记住,每个FnMut也是FnOnce:如果您有一个可以多次调用的函数,那么它也可以被调用一次。当然,FnMutFnOnce的结果应该是等效的。但是,没有办法从FnOnce返回借来的数据,因为它按值获取函数。在你的情况下,向量将被移动到函数,因为函数返回一个切片,而不是一个向量,它将无处可去,因此它将被销毁。因此,此类更改需要允许某些函数为FnMut / Fn,而不是FnOnce;我不确定这是否可取,甚至可能。

答案 1 :(得分:0)

这个问题可以通过使用trait本身来表达可能的功能来解决。

trait CallbackTrait {
    fn call(&mut self) -> &[u8];
}

fn make_callback() -> impl CallbackTrait {
    struct MyData(Vec<u8>);
    impl CallbackTrait for MyData {
        fn call(&mut self) -> &[u8] { &self.0 }
    }
    MyData(vec![0; 100])
}

而且,当您希望将其更通用地传递时,可以将其装箱。

fn make_another_callback() -> Box<dyn MyCallback> {
    Box::new<make_callback()>
}

由于没有API ,因此期望任何Fn(Once|Mut|)会在函数自身的生存期内返回某些内容,问题本身就是框架问题。您可能希望使用此功能的情况可以改用trait,但只需稍作更改即可,其好处是具有更大的灵活性,例如需要其他trait或具有多个功能。至于为什么语言本身不支持此概念,@ Vladimir Matveev对此做了解释。