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

标签 rust

这有效:

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/60525966/

相关文章:

web-services - 为什么我无法从 Internet 访问这个 Rust 简单服务器?

rust - "Sized is not implemented"是什么意思?

rust - 特征可以为其继承的特征的方法提供默认实现吗?

sql - Postgres和Rust R2D2 : How to get array_to_json as text/string without the escaped double quotes?

pointers - Rust 中的指针转换是否与 C++ 中的 reinterpret_cast 具有相同的行为?

rust - 什么特征阻止参数包含指向堆分配的数据的指针?

rust - 收集后Vec变异性不匹配

string - 如何将大十六进制字符串转换为十进制字符串?

rust - 为什么需要这种模式匹配?

rust - 在 Rust 中,Haskell 的 [n..m] 的惯用等价物是什么?