rust - 无法移动 dyn 类型的值 <'r> FnOnce(&' r mut [u8]) : the size of dyn for <'r> FnOnce(&' r mut [u8]) cannot be statically determined

标签 rust

我正在尝试在线程之间共享一个函数,可以用另一个函数调用它:

fn main() {
    let on_virtual_tun_write = std::sync::Arc::new(|f: &dyn FnOnce(&mut [u8]), size: usize|-> std::result::Result<(),()>{
        let mut buffer = vec![0; size];
        f(buffer.as_mut_slice());
        Ok(())
    });
}
一旦被调用,它就会使用 f作为参数传递,以检索缓冲区。如您所见,我不打算复制该函数,我只是在有人调用闭包时立即使用它,然后将其丢弃。但是,Rust 认为我想复制它。我该怎么做才能告诉 Rust 我只想使用对函数的引用?我以为&dyn就足够了。
错误:
error[E0161]: cannot move a value of type dyn for<'r> FnOnce(&'r mut [u8]): the size of dyn for<'r> FnOnce(&'r mut [u8]) cannot be statically determined
 --> src/main.rs:4:9
  |
4 |         f(buffer.as_mut_slice());
  |         ^

error[E0507]: cannot move out of `*f` which is behind a shared reference
 --> src/main.rs:4:9
  |
4 |         f(buffer.as_mut_slice());
  |         ^ move occurs because `*f` has type `dyn for<'r> FnOnce(&'r mut [u8])`, which does not implement the `Copy` trait

error: aborting due to 2 previous errors; 1 warning emitted

最佳答案

所以我认为有几个问题共同导致了这个问题。
我将使用一个简化的示例,它生成基本相同的错误消息。

fn main() { 
  let ff = |f: &dyn FnOnce()| { f(); };
}
问题的核心是 Rust 正在阻止错误代码,其中 FnOnce使用不止一次。像这样(不编译):
fn main() {
  let f = || {  }; // Imagine this is a real FnOnce()
  let ff = |f: &dyn FnOnce()| { f(); };
  ff(&f); // Use the FnOnce in our wrapper
  f(); // Use the FnOnce again - should fail to compile.
}
首先FnOnce()当被调用时会消耗它自己——这就是它如何确保它只能被调用一次。这意味着您需要传递对象,而不是对它的引用 - 否则调用者仍然可以持有引用。 Fn() 不是这种情况和 FnMut() .第一个只使用对 self 的引用,第二个使用对 self 的可变引用。这意味着以下编译正常:
fn main() { 
    let ff = |f: &dyn Fn()| { f(); };
    let f = || {};
    ff(f); // First call is OK
    f(); // Second usage is OK - it's a pure function

    let ff = |f: &mut dyn FnMut()| { f(); };
    let mut i = 0;
    let mut f = || { i += 1 };
    ff(&mut f); // OK i=1
    f(); // OK i=2
    println!("i={}", i); // prints 2

}
因此,如果您可以减少对函数类型的限制,使其为 FnFnMut ,那应该会为您解决问题,如果不是……请继续阅读。
您可以传递 FnOnce 的实例(不是引用)到使用 impl 的通用函数.例如
fn ff(f: impl FnOnce()) {
  f()
}

fn main() {
   // Creating a closure that moves q into it ensures we get a FnOnce
   let q=vec![1,2,3];
   let f = move || {println!("{}", q.len())};

   ff(f); // OK.
   // f(); // Compile error with "use of moved value: `f`"
}
这相当于
fn<F> ff(f: F)
    where F: FnOnce()
{
  f()
}
然而,我们不能以一种可以帮助我们的方式混合泛型和闭包。正在尝试使用 |f: impl FnOnce()|产生错误:error[E0562]: impl Trait not allowed outside of function and inherent method return types .
我认为您可以同时使用 FnOnce 的唯一方法闭包就是把函数装箱并传入。这会将函数的所有权转移到闭包中,所以我们称之为它。例如以下编译:
fn main() {
   let ff = |f: Box<dyn FnOnce()>| { f() };
   let q=vec![1,2,3];
   let f = Box::new(move || {println!("{}", q.len())});
   ff(f); // OK
   // f(); // Errors with "use of moved value: `f`"
}

关于rust - 无法移动 dyn 类型的值 <'r> FnOnce(&' r mut [u8]) : the size of dyn for <'r> FnOnce(&' r mut [u8]) cannot be statically determined,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66774134/

相关文章:

rust - 为什么 `impl Trait` 返回值实现 Send 而 `Box<dyn Trait>` 没有?

rust - 如何获取 Rust 中闭包的地址?

rust - 当 ref 和所有权转移都不起作用时如何返回

rust - 如何获取配置标志的值?

file - 在不立即将整个文件加载到内存中的情况下,分块读取大文件的最有效方法是什么?

generics - 简化具有重复关联类型限制的 where 子句

rust - 带有删除的双向链表?

rust - 如何根据整数格式化带缩进的字符串?

rust - 具有包含异步 block 的闭包的异步方法无法推断适当的生存期

rust - 结构体对象的生命周期比结构体成员的生命周期短