gpt4 book ai didi

rust - 闭包参数上未使用的类型参数

转载 作者:行者123 更新时间:2023-12-03 11:47:09 24 4
gpt4 key购买 nike

这有效:

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表现得像 & i32Cell一样。你会这样写:
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/65326000/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com