这有效:
struct Foo<T, F>
where
F: Fn() -> Option<T>,
{
f: F,
}
但这给了我编译错误:
struct Bar<I, T, F>
where
F: Fn(I) -> Option<T>,
{
f: F,
}
error[E0392]: parameter `I` is never used
--> src/lib.rs:1:12
|
1 | struct Bar<I, T, F>
| ^ unused parameter
|
= help: consider removing `I`, referring to it in a field, or using a marker such as `std::marker::PhantomData`
error[E0392]: parameter `T` is never used
--> src/lib.rs:1:15
|
1 | struct Bar<I, T, F>
| ^ unused parameter
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData`
为什么在闭包的返回类型中使用类型参数,但在其参数中不使用类型参数?
我可以通过将闭包存储为特征对象来解决它:
struct Bar<I, T> {
f: Box<Fn(I) -> Option<T>>,
}
但我想尽可能避免这种情况。
最佳答案
作为@VladimirMatveev says,闭包的返回类型是关联的类型。
关联的类型与类型参数不同,因为关联的值是在实现特征时确定的,而不是在调用中使用它时确定的。
在Fn(I) -> Option<T>
中,一旦有了输入(类型I
)和实现(您要传递的闭包中定义的特定操作),就确定了Option<T>
输出。
不过,对于I
来说却有所不同。您需要在结构中使用该类型,或者通过PhantomData
字段向编译器展示其在理论上的使用方式。
use std::marker::PhantomData;
struct Bar<I, T, F>
where
F: Fn(I) -> Option<T>,
{
f: F,
_marker: PhantomData<I>,
}
PhantomData
仅用于检查类型,但会在生成的代码中删除,因此它不会在结构中占用任何内存(这就是为什么它是幻像的原因)。在RFC 738 on variance中详细说明了需要它的原因。我会在这里尝试为您提供一个简短(希望是正确的)版本。
在Rust中,您可以在大多数情况下(但并非总是如此!)使用更长的生命周期,而预期生命周期会更短。
fn foo<'short, 'long>(_a: &'short i32, b: &'long i32)
where
'long: 'short,
{
let _shortened: &'short i32 = b; // we're binding b to a shorter lifetime
}
fn foo2<'short, 'long>(_a: &'short i32, b: &'long Cell<&'long i32>)
where
'long: 'short,
{
let _shortened: &Cell<&'short i32> = b;
}
(playground)
RFC解释了为什么
Cell
期望生命周期完全相同(而不是更长),但是现在我建议您只相信编译器,允许foo2
进行编译是不安全的。现在假装你有一个
struct Foo<T> { t: T }
该
T
可以是任何东西,包括保存引用的类型。特别地,
T
可以是类似于& i32
的类型,也可以是诸如&Cell<&i32>
的类型。与上面的
foo
函数一样,Rust可以通过检查T
(playground)的类型来推断是否可以允许我们分配较短的生存期。但是,当您有未使用的类型参数时,推断没有任何字段可检查以了解其应如何允许该类型具有生存期。
如果你有
struct Foo<T>; // unused type parameter!
Rust要求您使用
PhantomType
进行指定,如果您希望自己的T
表现得像& i32
或Cell
一样。你会这样写:struct Foo<T> {
marker: PhantomData<T>, // this is what you usually want
// unless you're working with unsafe code and
// raw pointers
}
或者你可以写:
struct Foo<T> {
marker: PhantomData<Cell<T>>
}
关于rust - 闭包参数上未使用的类型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60525966/