问题描述
trait FnBox {fn call_box(self: Box);}impl<F: FnOnce()>FnBox 为 F {fn call_box(self: Box) {(*自己)()}}fn 主(){让作业:Box= Box::new(|| {});//编译的版本//let job = Box::new(|| {});//让作业:Box= Box::new(|| {});job.call_box();}
job.call_box();
不编译:
error[E0599]: 没有为类型`std::boxed::Box<std::ops::FnOnce()>找到名为`call_box`的方法.` 在当前范围内-->src/main.rs:16:9|16 |job.call_box();|^^^^^^^^^|= 注意:job 是一个函数,也许你想调用它= 注意:方法`call_box` 存在,但不满足以下特征边界:`std::ops::FnOnce() : FnBox`= help: 来自traits的项目只有在trait被实现并且在范围内时才能使用= 注意:以下特征定义了一个项目`call_box`,也许你需要实现它:候选 #1:`FnBox`
为什么编译器在此处看不到到 FnBox
的转换?
我想当我使用 let job = Box::new(|| {});
时会导致 Box
类型.编译器设法解析 job.call_box()
,即 Box
-> Box
-> Box
(因为 FnBox
是为 FnOnce()
实现的,而不是为 closure
实现的).为什么不只是 Box
-> Box
工作?
FnBox
没有为 FnOnce()
实现.
FnOnce()
有两个含义:作为特征和作为类型.在 Box
中,它是一个(动态的,未调整大小的)类型.自 Rust 1.27 起,该类型可以更明确地写为 dyn FnOnce()
. 对于这个答案的其余部分我将使用 dyn
以便在我谈论特征和动态类型时说清楚.
您编写的 impl
没有为 dyn FnOnce()
类型实现 FnBox
,因为 通用参数有一个隐式的Sized
绑定.如果我们遵循该问题的答案的建议并将 + ?Sized
添加到 F
,编译器确实会给出稍微有用的错误消息:
implFnBox 为 F {fn call_box(self: Box) {(*自己)()}}
error[E0161]: 无法移动 F 类型的值:无法静态确定 F 的大小-->src/main.rs:7:9|7 |(*自己)()|^^^^^^^^
明确指出需要 Sized
ness 的地方.
在 1.35 之前的 Rust 版本中,没有办法修复这个错误;FnOnce()
的 trait 对象毫无用处.但是,今天Box
实现了FnOnce()
,所以你可以像普通闭包一样调用它,不用使用*
:
implFnBox 为 F {fn call_box(self: Box) {自己()}}
另见
- 什么是Box;"在 Rust 中是什么意思?
- Rust Trait 对象转换(为什么你不能从一种 trait 对象类型转换为另一个)
trait FnBox {
fn call_box(self: Box<Self>);
}
impl<F: FnOnce()> FnBox for F {
fn call_box(self: Box<F>) {
(*self)()
}
}
fn main() {
let job: Box<FnOnce()> = Box::new(|| {});
// versions that compile
// let job = Box::new(|| {});
// let job: Box<FnBox> = Box::new(|| {});
job.call_box();
}
job.call_box();
doesn't compile:
Why doesn't the compiler see the conversion to FnBox
here?
I suppose when I use let job = Box::new(|| {});
that results in a Box<closure>
type. The compiler manages to resolve job.call_box()
, which is Box<closure>
-> Box<FnOnce()>
-> Box<FnBox>
(because FnBox
is implemented for FnOnce()
, not for closure
). Why doesn't just Box<FnOnce()>
-> Box<FnBox>
work?
FnBox
isn't implemented for FnOnce()
.
FnOnce()
has two meanings: as a trait, and as a type. In Box<FnOnce()>
, it's a (dynamic, unsized) type. Since Rust 1.27, the type can be written more explicitly as dyn FnOnce()
. For the rest of this answer I will use dyn
in order to make clear when I'm talking about the trait and when about the dynamic type.
The impl
you wrote doesn't implement FnBox
for the type dyn FnOnce()
, because generic parameters have an implicit Sized
bound. If we follow the advice of that question's answer and add + ?Sized
to F
, the compiler does give a slightly more helpful error message:
impl<F: FnOnce() + ?Sized> FnBox for F {
fn call_box(self: Box<F>) {
(*self)()
}
}
error[E0161]: cannot move a value of type F: the size of F cannot be statically determined
--> src/main.rs:7:9
|
7 | (*self)()
| ^^^^^^^
Which does explicitly call out the place where Sized
ness is required.
In versions of Rust before 1.35, there was no way to fix this error; trait objects of FnOnce()
were just useless. However, today Box<dyn FnOnce()>
implements FnOnce()
, so you can call it like a normal closure, without using *
:
impl<F: FnOnce() + ?Sized> FnBox for F {
fn call_box(self: Box<F>) {
self()
}
}
See also
- What does "Box<Fn() + Send + 'static>" mean in Rust?
- Rust Trait object conversion (why you can't go from one trait object type to another)
这篇关于`Box`ed 类型的方法调用解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!