cmp::Eq是否有意为之实现了fn(&'a T) -> T但没有实现fn(&T) -> T?

6

Rust 1.25.0中的以下有效代码段如下:

use std::marker::PhantomData;

trait Foo {
    type Eq: Eq;
}

struct Bar<'a>(PhantomData<&'a u8>);

impl<'a> Foo for Bar<'a> {
    type Eq = fn(&'a u32) -> u32;
}

如您在Rust Playground上所见,这表明Eq适用于fn(&'a T) -> T

如果我们做出非常小的更改,删除相关类型的生命周期:

use std::marker::PhantomData;

trait Foo {
    type Eq: Eq;
}

struct Bar<'a>(PhantomData<&'a u8>);

impl<'a> Foo for Bar<'a> {
    type Eq = fn(&u32) -> u32;
}

我们可以看到,fn(&u32) -> u32没有实现Eq请查看
error[E0277]: the trait bound `for<'r> fn(&'r u32) -> u32: std::cmp::Eq` is not satisfied
 --> src/main.rs:9:10
  |
9 | impl<'a> Foo for Bar<'a> {
  |          ^^^ the trait `std::cmp::Eq` is not implemented for `for<'r> fn(&'r u32) -> u32`
  |
  = help: the following implementations were found:
            <extern "C" fn(A) -> Ret as std::cmp::Eq>
            <unsafe fn(A) -> Ret as std::cmp::Eq>
            <extern "C" fn(A, ...) -> Ret as std::cmp::Eq>
            <unsafe extern "C" fn(A, ...) -> Ret as std::cmp::Eq>
          and 2 others

这是故意的吗,还是疏忽了应该实现的内容,或者是一个错误?

fn 的源代码来看,他们使用原始指针等价性实现 PartialEq,也就是说,如果地址相同,则必须是相同的函数。那为什么对于 fn(&T) -> T 不能成立呢?

对我提出的一种选择是, fn(&T) -> T 是针对参数的生命周期进行泛型化处理,因此在逻辑上无法成为 Eq 。而 fn(&'a T) -> T 不是通用的,因为生命周期已被指定为'a。但我不太确定我是否接受/理解这个假设,所以如果有人有一个好的论点,我也会接受。


fn(&'a T) -> T不是泛型的” — 是的,它是。 'a 是一个泛型生命周期参数。因此,这种推理似乎站不住脚。 - Shepmaster
1个回答

2
可能是因为当你比较两个fn(&T) -> T时,你实际上在比较一个fn(&'a T) -> T和一个fn(&'b T) -> T,没有办法检查生命周期'a'b是否相同,而当你比较两个fn(&'a T) -> T时,你知道生命周期是相同的。

注意:这只是我的猜测,我没有权威的信息。


两个 fn(&T) -> T 不是应该分别是 fn<'b>(&'b T) -> T 以及 fn<'c>(&'c T) -> T 吗?如果这两个函数不同,你会在什么情况下使用它们呢?换句话说,它们不应该被实现成相同的函数吗? - Emoun
当您比较它们时,它们不再是泛型:所有泛型参数(包括生命周期)都已解析。如果所有泛型参数都已解析为相同的值,则可以进行比较。否则,将无法比较它们(与无法比较u8u32的原因相同)。 - Jmb
我从类型理论的角度看到了这一点,但它是否会解决2个不同函数的问题?此外,使用newtypes手动实现指针等价性的Eq是否存在任何不安全性? - Emoun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接