在使用框闭包时,我遇到了以下问题:
type Test = Rc<dyn Fn() -> i64>;
fn test_bad() -> Test {
Test::new(|| 42)
}
fn test_good() -> Test {
Rc::new(|| 42)
}
在第一种情况下,我使用类型别名来引用new
方法,而在第二种情况下,我直接使用Rc
。
在第一种情况下,编译器报错:
| Test::new(|| 42)
| ^^^ function or associated item not found in `Rc<(dyn Fn() -> i64 + 'static)>`
|
= note: the method `new` exists but the following trait bounds were not satisfied:
`dyn Fn() -> i64: Sized`
但是第二种情况很好。有人能解释一下这两者的区别吗?是否有任何方法可以通过类型别名引用new
,或者我需要自己包装它?
在test_good
中,通过在|| 42
上调用Rc::new
,您不创建一个Rc<dyn Fn() -> i64>
,但是一个Rc<ClosureType>
,其中ClosureType
是所提供闭包的唯一类型,并且是大小的。然后,由于Rc<ClosureType>
是在返回Rc<dyn Fn() -> i64>
的函数中返回的,因此它将其隐式地强制转换为trait对象。
test_bad
失败了,因为它不是从构造一个有大小的闭包的Rc
然后将其强制转换为一个没有大小的trait对象的Rc
,而是试图直接构造一个没有大小的trait对象的Rc
,这失败了,因为函数的所有参数都必须有大小。
我不认为有一个直接的方法来引用new
通过类型别名,虽然你可以很容易地创建自己的:
fn new_test(func: impl 'static + Fn() -> i64) -> Test {
Rc::new(func)
}
泛型类型别名有效,但具体类型别名失败:
use std::rc::Rc;
type MyGenericRc<T> = Rc<T>;
// works
fn construct_with_generic_alias() -> MyGenericRc<dyn Fn() -> i64> {
MyGenericRc::new(|| 42)
}
type MyConcreteRc = Rc<dyn Fn() -> i64>;
// fails
fn construct_with_concrete_alias() -> MyConcreteRc {
MyConcreteRc::new(|| 42)
}
当你调用MyGenericRc::new(<closure>)
时,编译器选择Rc::<closure type>::new(<closure>)
作为要使用的具体函数实现,因为Rc::new
需要Sized
参数,并且每个匿名闭包类型都是Sized
。然而,在调用该函数之后,编译器执行取消大小强制转换将返回的Rc<anonymous closure type>
转换为Rc<dyn Fn() -> i64>
。
当你调用MyConcreteRc::new(<closure>)
时,你不让编译器决定使用哪个Rc::new
实现,你告诉它必须使用Rc::<dyn Fn() -> i64>::new
,但它不可能满足该实现的类型要求,因为new
期望Sized
参数,但dyn Fn() -> i64
是!Sized
,因此你看到的编译错误消息。