调用Rust中存储在结构中的堆栈分配的闭包 [英] Calling a Stack-Allocated Closure Stored in a Struct in Rust

查看:34
本文介绍了调用Rust中存储在结构中的堆栈分配的闭包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将闭包存储在这样的结构中:

 #[derive(Clone)]结构S< a>{func:&'a FnOnce()->u32}fn main(){令s = S {func:& ||0};let val =(s.func)();println!("{}",val);} 

编译时, s.func 无法移动以执行自身.我知道为什么不能移动它(即,它仅是一个引用,并且在编译时不知道其大小),但不知道为什么要移动它-仅仅是因为闭包是通过traits实现的?/p>

这是错误消息:

 错误[E0161]:无法移动类型为std :: ops :: FnOnce()->的值.u32:std :: ops :: FnOnce()的大小->无法静态确定u32->main.rs:8:15|8 |let val =(s.func)();|^^^^^^^^^错误[E0507]:无法移出借用的内容->main.rs:8:15|8 |let val =(s.func)();|^^^^^^^^^无法移出借用的内容错误:由于2个先前的错误而中止 

这是解决此问题的唯一方法吗(通过 Box< Box< FnOnce()-> u32> )存储在堆上?为什么调用闭包会移动它呢?大概调用它不会改变函数本身.

解决方案

由于 Fn :: call 通过引用和self rel ="nofollow noreferrer"> FnMut :: call_mut 通过可变引用获取 self .由于两者都接受引用,因此可以将特征对象与它们一起使用.

I am storing a closure in a struct like this:

#[derive(Clone)]
struct S<'a> {
    func: &'a FnOnce() -> u32
}

fn main() {
    let s = S { func: &|| 0 };
    let val = (s.func)();
    println!("{}", val);
}

When I compile, s.func cannot be moved to execute itself. I understand why it cannot be moved (namely that it's only a reference and that its size is not known at compile time), but don't know why it's being moved at all -- is it just because closures are implemented via traits?

Here's the error message:

error[E0161]: cannot move a value of type std::ops::FnOnce() -> u32:
the size of std::ops::FnOnce() -> u32 cannot be statically determined
 --> main.rs:8:15
  |
8 |     let val = (s.func)();
  |               ^^^^^^^^

error[E0507]: cannot move out of borrowed content
 --> main.rs:8:15
  |
8 |     let val = (s.func)();
  |               ^^^^^^^^ cannot move out of borrowed content

error: aborting due to 2 previous errors

Is this only way the solve this to store the closure on the heap (via Box<FnOnce() -> u32>)? And why does calling a closure move it? Presumably calling it doesn't mutate the function itself.

解决方案

The closure is being moved because FnOnce::call_once takes self by value. This contract enforces the guarantee that the function will not be called more than once.

If you will indeed be calling the closure at most once, and you want to use the FnOnce trait, then your struct needs to take ownership of that closure (and you will need to make your struct generic on the closure type). Note that calling the closure will move the closure out of your struct, thereby invalidating the whole struct; you may work around that by wrapping the FnOnce in an Option and take-ing the closure out of the Option before calling it.

If you might be calling the closure more than once, you don't want to take ownership of the closure, or you don't want to make your struct generic on the closure type, then you should use either Fn or FnMut instead. Fn::call takes self by reference and FnMut::call_mut takes self by mutable reference. Since both accept references, you can use trait objects with them.

这篇关于调用Rust中存储在结构中的堆栈分配的闭包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆