Skip to content

5.9 supertrait

有时候,我们可能需要在一个 trait 中使用另一个 trait 的功能。这时候将依赖所使用的 trait 也需要被实现。

这个所依赖的 trait 被称为我们所定义的 trait 的 supertrait(超级 trait)。 一个 trait 可以有一个或者多个 supertraits,它们可以被用来约束实现了子 trait 的类型。

示例:

rust
use std::fmt::{Debug, Display};

trait Foo: Debug + Display {
    // trait 方法定义
}

在这个例子中,通过使用+运算符来同时指定多个超级 trait,可以让Foo trait 具有这些超级 trait 中定义的所有方法和行为特征,从而增强了其功能和灵活性。

假如,我们定义了一个包含 outline_print 方法的 trait OutlinePrint,我们希望它可以打印出带有星号框的值。 也就是说,如果 Point 实现了 Display trait 并返回(x, y),当我们调用Point(1,3)实例的 outline_print 方法时会显示:

txt
**********
*        *
* (1, 3) *
*        *
**********

outline_print 的实现中,我们希望能够使用 Display trait 的功能。因此,我们需要指明 OutlinePrint trait 只能用于实现了 Display trait 并提供了 OutlinePrint 需要的功能的类型。 我们可以通过在 trait 定义中使用类似 OutlinePrint: Display 来做到这一点。

参考下面的例子:

rust
use std::fmt;

trait OutlinePrint: fmt::Display {
    fn outline_print(&self) {
        let output = self.to_string();
        let len = output.len();
        println!("{}", "*".repeat(len + 4));
        println!("*{}*", " ".repeat(len + 2));
        println!("* {} *", output);
        println!("*{}*", " ".repeat(len + 2));
        println!("{}", "*".repeat(len + 4));
    }
}

因为我们指定了 OutlinePrint trait 需要依赖 Display trait,所以我们可以在 outline_print 方法中使用 Display trait 中的 to_string 方法, 任何实现了 Display trait 的类型会实现该方法。

如果不在 trait 名后增加 :Display并尝试在 outline_print 中调用to_string方法,则会产生错误。 下面让我们尝试在一个没有实现 Display trait 的类型上实现 OutlinePrint trait ,看看会发生什么:

rust
struct Point {
    x: i32,
    y: i32,
}

impl OutlinePrint for Point {}

我们将得到类似下面的编译时错误:

error[E0277]: `Point` doesn't implement `std::fmt::Display`

我们可以通过在 Point 上实现 Display trait 来满足 OutlinePrint trait 的要求,以解决这个错误。

解决示例:

rust
use std::fmt;

trait OutlinePrint: fmt::Display {
    fn outline_print(&self) {
        let output = self.to_string();
        let len = output.len();
        println!("{}", "*".repeat(len + 4));
        println!("*{}*", " ".repeat(len + 2));
        println!("* {} *", output);
        println!("*{}*", " ".repeat(len + 2));
        println!("{}", "*".repeat(len + 4));
    }
}

struct Point {
    x: i32,
    y: i32,
}

// 实现 Display trait 来满足要求
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

impl OutlinePrint for Point {}


fn main() {
   let p = Point { x:1, y:3 } ;
   p.outline_print()
}

现在我们可以成功编译了,并可以在 Point 实例上调用outline_print方法来显示它。

Released under the MIT License