闭包参数上未使用的类型参数 [英] Unused type parameter on closure argument

查看:54
本文介绍了闭包参数上未使用的类型参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这有效:

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`

为什么在闭包的返回类型中可以使用类型参数,而在其参数中却不能?

Why is using a type parameter in the closure's return type ok, but not in its arguments?

我可以通过将闭包存储为 trait 对象来绕过它:

I can get around it by storing the closure as a trait object:

struct Bar<I, T> {
    f: Box<Fn(I) -> Option<T>>,
}

但我想尽可能避免这种情况.

but I'd like to avoid this if possible.

推荐答案

As @VladimirMatveev 说,闭包的返回类型是关联类型.

As @VladimirMatveev says, the return type of a closure is an associated type.

关联类型与类型参数不同,因为它的值是在您实现特征时确定的,而不是在调用中使用时确定的.
Fn(I) ->Option,一旦你有了输入(I 类型)和实现(你传递的闭包中定义的特定操作),Option; 输出确定.

An associated type is different from a type parameter because its value is determined when you implement a trait, not when you use it in a call.
In Fn(I) -> Option<T>, once you have the input (of type I) and the implementation (the particular operations defined in the closure you're passing), the Option<T> output is determined.

对于 I 来说,情况有所不同.您需要使用结构中的类型,或者向编译器显示理论上如何使用,并带有一个 PhantomData 字段.

For I it's different, though. You need to either use the type in the struct, or to show the compiler how it would be theoretically used, with a PhantomData field.

use std::marker::PhantomData;

struct Bar<I, T, F>
where
    F: Fn(I) -> Option<T>,
{
    f: F,
    _marker: PhantomData<I>,
}

PhantomData 仅用于检查类型,但在生成的代码中被擦除,因此它不会占用您结构中的任何内存(这就是为什么它是幻影的原因).

PhantomData is only used to check types, but is erased in the generated code, so it does not occupy any memory in your struct (that's why it's a phantom).

需要的原因在关于差异的 RFC 738.我会尽量在这里给你一个更短的(希望是正确的)版本.

The reason why it is needed is explained in detail in RFC 738 on variance. I'll try to give you a shorter (and hopefully correct) version here.

在 Rust 中,您可以在大多数情况下(但并非总是如此!)使用更长的生命周期,而预期生命周期会更短.

In Rust, you can most of the times (but not always!) use a longer lifetime where a shorter one is expected.

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;
}

(游乐场)

RFC 解释了为什么 Cell 期望完全相同(而不是更长)的生命周期,但现在我建议您只相信编译器允许 foo2 是不安全的代码>编译.

The RFC explains why Cell expects exactly the same (and not a longer) lifetime, but for now I suggest you just trust the compiler that it would be unsafe to allow foo2 to compile.

现在假装你有一个

struct Foo<T> { t: T }

T 可以是任何东西,包括保存引用的类型.
特别是,T 可以是类似 & 的类型.i32 或类似 &Cell<&i32>.
与上面的 foo 函数一样,Rust 可以通过检查 T 的类型(playground).

That T can be anything, including a type that holds references.
In particular, T can be a type like & i32 or a type like &Cell<&i32>.
As with our foo functions above, Rust can infer just fine when it can or can't allow us to assign to a shorter lifetime by inspecting the type of T (playground).

但是,当您有一个未使用的类型参数时,推理没有任何要检查的字段来了解它应该如何允许类型在生命周期内表现.

However, when you have an unused type parameter, inference does not have any field to inspect to know how it should allow the type to behave with lifetimes.

如果你有

struct Foo<T>; // unused type parameter!

Rust 要求您使用 PhantomType 指定是否希望 T 表现得像 &i32 或类似 Cell.你会写:

Rust asks you to specify with a PhantomType if you wish your T to behave as if it was a & i32 or like a Cell. You would write:

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>>
}

这篇关于闭包参数上未使用的类型参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆