无法从回调向量调用函数,获取"预期函数,找到 'Box<std::ops::FnMut(T) + 'a>'



我正试图在Rust 1.11中实现一个回调系统。我想我已经设置好了存储回调的系统,但我在实际调用它们时遇到了问题。示例代码:

struct Container<'a, T> {
callbacks: Vec<Box<FnMut(T) + 'a>>,
}
impl<'a, T: Copy + PartialEq> Container<'a, T> {
fn new() -> Self {
Container {
callbacks: Vec::new(),
}
}
fn add_callback<F: 'a + FnMut(T)>(&mut self, callback: F) -> usize {
let cb_id = self.callbacks.len();
self.callbacks.push(Box::new(callback));
cb_id
}
fn call_by_id(&self, cb_id: usize, value: T) {
// This doesn't work and I don't know why:
self.callbacks[cb_id](value);
// It still doesn't work (same error) when I try to dereference the Box
// *self.callbacks[cb_id](value);
// It's not a dereferencing scoping issue, either
// *(self.callbacks[cb_id])(value);
}
}
fn main() {
let mut list = Vec::new();
{
let mut container = Container::new();
let append = container.add_callback(|v| list.push(v));
container.call_by_id(append, 3);
container.call_by_id(append, 4);
}
println!("List contains: {:?}", list);
// Expect "List contains: [3, 4]", but it doesn't compile
}

(游乐场链接)

这会产生以下错误:

error: expected function, found `Box<std::ops::FnMut(T) + 'a>`
--> <anon>:20:9
|>
20 |>         self.callbacks[cb_id](value);
|>         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

对于Rust来说,这是异常无益的;我真的很难通过谷歌或在这里搜索找到这个错误的其他例子。

Box文档声称有一个通用的impl<T> Deref for Box<T> where T: ?Sized,而Sized文档则表示语法?Sized用于删除Sized特性的要求。我理解这意味着,Box为每个T实现Deref,无论大小,所以它应该在这里发挥作用。

如果是这样的话,我根本不明白为什么我不能直接调用包含回调的Box,或者(最坏的情况)取消引用self.callbacks[cb_id]来访问可调用的。我目前最好的猜测是,这与游戏中的一生有关,但如果是这样,我只是不知道如何调整它们以使其发挥作用。

这里有一个较小的复制:

fn main() {
let a: Vec<Box<FnMut()>> = vec![Box::new(|| println!("called"))];
a[0]();
}

让我们将其分解并观察类型和错误:

fn call_by_id(&self, cb_id: usize, value: T) {
let () = self.callbacks[cb_id];
}

这表明该类型为Box<std::ops::FnMut(T)>。到目前为止,一切都很好。将其存储在变量中并继续:

fn call_by_id(&self, cb_id: usize, value: T) {
let x = self.callbacks[cb_id];
x(value);
}

啊,对:error: cannot borrow immutable `Box` content `*x` as mutable。。。

fn call_by_id(&self, cb_id: usize, value: T) {
let mut x = self.callbacks[cb_id];
x(value);
}

Oops:error: cannot move out of indexed content。。。

fn call_by_id(&self, cb_id: usize, value: T) {
let mut x = &mut self.callbacks[cb_id];
x(value);
}

啊哈:error: cannot borrow immutable field `self.callbacks` as mutable。。。

fn call_by_id(&mut self, cb_id: usize, value: T) {
let mut x = &mut self.callbacks[cb_id];
x(value);
}

它编译了我可能会把它留在这里(x的名字更好),但让我们看看是否可以把它放回一行。直接替代:

fn call_by_id(&mut self, cb_id: usize, value: T) {
(&mut self.callbacks[cb_id])(value);
}

不,回到error: expected function, found `&mut Box<std::ops::FnMut(T) + 'a>`也许是一个取消引用:

fn call_by_id(&mut self, cb_id: usize, value: T) {
(*self.callbacks[cb_id])(value);
}

没有,error: cannot borrow immutable信箱content as mutable。更具体地说可变性:

fn call_by_id(&mut self, cb_id: usize, value: T) {
(*&mut self.callbacks[cb_id])(value);
}

这很有效,但我不确定它是否优雅。


总之,问题是回调的变量是不可变的。这是由两件事引起的:

  1. 回调向量的结合是不可变的(通过&self)
  2. 回调的取消引用似乎不理解可变性要求,除非您是明确的。我不能百分之百确定为什么会这样

请注意,在您的注释代码中:

*self.callbacks[cb_id](value);
*(self.callbacks[cb_id])(value);

我确信这些都是一样的;*的优先级将把它绑定到整个值的结果。我想你的意思是:

(*self.callbacks[cb_id])(value);

最新更新