在Rust语言中定义空的impl有什么目的?

4
例如:
impl<T: ?Sized> cmp::Eq for $t<T> {}

如果代码没有实现,你为什么要写它?这种情况在许多地方都会发生,特别是与Eq有关的情况。

#[unstable(feature = "structural_match", issue = "31434")]
impl<T: ?Sized> StructuralPartialEq for $t<T> {}

#[unstable(feature = "structural_match", issue = "31434")]
impl<T: ?Sized> StructuralEq for $t<T> {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Copy for $t<T> {}

impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
unsafe impl<T: ?Sized> Freeze for *const T {}
unsafe impl<T: ?Sized> Freeze for *mut T {}
unsafe impl<T: ?Sized> Freeze for &T {}
unsafe impl<T: ?Sized> Freeze for &mut T {}

你能指出一个Ord的例子吗?我不明白如果不实现fn cmp(&self, other: &Self) -> Ordering;它是如何实现的。 - John Kugelman
你说得对,我实际上没有看到它适用于Ord。 - Lance
2个回答

7
如果一个特质没有方法或者所有的方法都有默认实现,那么可以使用空的 impl {} 块来实现它。这些被称为“标记”或“标签”特质。 无开销的抽象:Rust 中的特质中对标记特质有描述:

Rust 有一些将类型分类的“标记”:SendSyncCopySized。这些标记只是带有空体的特质,可以在泛型和特质对象中使用。标记可以在库中定义,并自动提供类似于 #[derive] 的实现:例如,如果一个类型的所有组件都是 Send,那么该类型也是 Send。正如我们之前所看到的,这些标记可以非常强大:Rust 如何保证线程安全就是通过 Send 标记实现的。

Eq 是另一个常见的标记特征。它是用于已经实现了 PartialEq 的类型的标记,表示相等操作实际上不是“部分相等”,而是完全的自反、对称和传递性。实现它不需要任何额外的实现,因为 eq 实现是从类型的 impl PartialEq { ... } 块中获取的。

pub trait Eq: PartialEq<Self> { }

Trait for equality comparisons which are equivalence relations.

This means, that in addition to a == b and a != b being strict inverses, the equality must be (for all a, b and c):

  • reflexive: a == a;
  • symmetric: a == b implies b == a; and
  • transitive: a == b and b == c implies a == c. This property cannot be checked by the compiler, and therefore Eq implies PartialEq, and has no extra methods.
Derivable

This trait can be used with #[derive]. When derived, because Eq has no extra methods, it is only informing the compiler that this is an equivalence relation rather than a partial equivalence relation. Note that the derive strategy requires all fields are Eq, which isn’t always desired.

How can I implement Eq?

If you cannot use the derive strategy, specify that your type implements Eq, which has no methods:

enum BookFormat { Paperback, Hardback, Ebook }
struct Book {
    isbn: i32,
    format: BookFormat,
}
impl PartialEq for Book {
    fn eq(&self, other: &Self) -> bool {
        self.isbn == other.isbn
    }
}
impl Eq for Book {}

我发布的其他示例呢? - Lance
同样的事情 - 它可能是一个没有方法的标记特征,或者所有的方法都有一些默认实现,没有理由覆盖它们(例如 std::error::Error)。 - Cerberus

2
并非每个特性都需要定义方法。有些特性具有所有默认实现的方法,而其他一些特性则根本没有方法。
然而,Rust 仍然需要明确地告诉任何给定类型实现一个特性。Rust 不使用“鸭子类型”(例如 golang 中的方式)来隐式实现特性,如果存在正确的方法签名,则必须始终显式地实现特性。这样做有很好的设计理由,但如果您感兴趣,可以单独进行研究。
因此,对于仅使用默认方法实现或根本没有方法的特性进行实现,仍然需要编写 impl 块。当然,在这些情况下,该 impl 块将为空,因为它所说的只是“struct Foo 实现了特性 Bar”,编译器不需要更多的信息。
有很多好的理由编写不需要定义方法的特质。一个常见的原因是“标记特质”,它仅仅标记类型的某些属性、行为或特性,而不需要任何方法来证明这一点。另一个相当常见的原因是密封特质,它允许你拥有一个pub特质(使用户可以看到和使用其中的方法),但是除了你自己的包之外,其他人无法impl它(这样你就可以保证实现该特质的任何类型都是你所控制的)。

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