20、Orphan Rule(孤儿规则)

孤儿规则

实现traits

你不能对另外的crate里面的类型定义新的方法,比如:

impl u32 {
    fn is_even(&self) -> bool {
        self % 2 == 0
    }
}

编译器会报错

error[E0390]: cannot define inherent `impl` for primitive types
  |
1 | impl u32 {
  | ^^^^^^^^
  |
  = help: consider using an extension trait instead

拓展trait

拓展trait是一种trait,它的主要目的是将新的方法附加给外部的类型,例如u32,上一个的练习就实现了。

通过定义IsEventrait,并且为i32u32类型实现这个trait。然后我们就可以自由的为这些类型调用is_even()了,只要Is_Even这个trait在作用域。

// Bring the trait in scope
use my_library::IsEven;

fn main() {
    // Invoke its method on a type that implements it
    if 4.is_even() {
        // [...]
    }
}

只有一个实现

我们可以编写的trait存在限制。

最简单,最直接的限制就是,我们不能在一个trait里,对同一个类型实现相同的两个trait:

trait IsEven {
    fn is_even(&self) -> bool;
}

impl IsEven for u32 {
    fn is_even(&self) -> bool {
        true
    }
}

impl IsEven for u32 {
    fn is_even(&self) -> bool {
        false
    }
}

 

编译器会拒绝编译

error[E0119]: conflicting implementations of trait `IsEven` for type `u32`
   |
5  | impl IsEven for u32 {
   | ------------------- first implementation here
...
11 | impl IsEven for u32 {
   | ^^^^^^^^^^^^^^^^^^^ conflicting implementation for `u32`

 

在对u32值调用IsEven::is_even时,应使用哪种trait不能有任何歧义,因此这里只能由一个trait实现。

孤儿规则

当涉及到多个crates时,事情就会很微妙。尤其是,以下的任意一个条件至少满足一个:

  • trait 是在当前 crate 中定义的
  • 实现的类型(就是给哪个类型实现的trait)是在当前 crate 中定义的

(trait的实现就是两个主体,一个是定义trait,一个是给特定类型实现trait,只要确保这两个主体不会同时出现在多个trait里面就行)

 

这就是Rust的孤儿规则,它的目的是让方法解析的过程准确无误。

 

举个例子:

  • crate A 实现了 IsEven trait
  • crate B 为 u32 实现了 IsEven trait
  • crate C 为 u32 实现了一个不同的 IsEven trait
  • create D 依赖于B和C,并调用 1.is_even()

在这个时候,D的调用不确定应该使用哪个trait,是B的?还是C的?

Rust编译器无法决定,所以Rust设置了孤儿规则来防止这种情况的发生。所以,因为孤儿规则,crate B和crate C都无法编译。

练习

这次练习的题目是:

// TODO: this is an example of an orphan rule violation.
//  We're implementing a foreign trait (`PartialEq`, from `std`) on
//  a foreign type (`u32`, from `std`).
//  Look at the compiler error to get familiar with what it looks like.
//  Then delete the code below and move on to the next exercise.

impl PartialEq for u32 {
    fn eq(&self, _other: &Self) -> bool {
        
    }
}

基于孤儿规则的练习,查看编译器错误,然后删掉代码?

image-20250909091820760

编译器说,impl doesn't have any local type before any uncovered type parameters

既然不能给u32重写这个trait,那干脆别写了,全删喽!

 

嘿嘿,过了(

 

以上,就是这一节的学习内容了

 

阅读剩余
THE END