为什么Box包裹的闭包可像普通闭包调用?相关报错如何解决?
问题解答
代码报错原因及修复
你定义的闭包捕获了可变变量x,属于FnMut trait的实现者,使用(&mut ww)()的调用方式引入了额外的引用层级,触发了错误的trait匹配规则,编译器误以为你需要Fn trait的实现,因此抛出错误。
修复方案非常简单,直接调用Box实例即可:
fn main() { let mut x = String::new(); let y = || { let t = &mut x; }; let mut ww = Box::new(y); // 直接调用Box包裹的闭包即可 ww(); }
Box包裹闭包的调用原理
Box包裹的闭包调用表现和普通闭包一致,有两层原因:
- 标准库内置Fn系列trait实现:Rust标准库为
Box<F>泛型实现了全部三个闭包相关trait,只要内部的闭包类型F实现了FnOnce/FnMut/Fn中的任意一个,对应的Box<F>也会自动实现相同的trait,因此可以直接像调用普通闭包一样调用Box实例。 - Deref trait自动转换:就算没有上述的内置trait实现,Box作为智能指针实现了
Dereftrait,调用时Rust的自动解引用 coercion 会将Box<F>自动转换为&F/&mut F,匹配到内部闭包的调用方法,表现和普通闭包一致。
Deref trait对所有智能指针的适用性
只要是符合智能指针定义的类型,都可以通过实现Deref trait获得自动解引用能力,这个特性是通用的。不过要注意,如果要让智能指针包裹的闭包可以直接调用,要么该智能指针像Box一样内置了Fn系列trait的泛型实现,要么调用时可以通过自动解引用拿到内部的闭包实例。比如Rc<F>、Arc<F>等标准库智能指针,都内置了对应的闭包trait实现,调用表现和普通闭包、Box包裹的闭包完全一致。
内容的提问来源于stack exchange,提问作者raj
相关产品推荐
相关产品推荐

