如何在类型已实现 Display 的特征对象上实现 Display

Bob*_*Bob 7 traits rust

我有一些代码返回类型的特征对象MyTrait,以便它可以返回几个不同的结构之一。我想实现Display特征对象的特征,以便我可以打印该对象,并将详细信息委托给各种结构,因为它们每个都需要自己的自定义格式化程序。

我可以通过将格式化方法作为MyTrait定义的一部分,然后实现DisplayforMyTrait和委托来实现这一点 - 如下所示:

trait MyTrait {
    fn is_even(&self) -> bool;
    fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
}

impl fmt::Display for MyTrait {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.my_fmt(f)
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我已经Display为每个实现的结构实现了该特征MyTrait。这意味着我最终为每个结构体提供了两个执行相同操作的方法 -直接在结构体上fmt()满足特征的方法,以及由上面的代码调用的方法。这看起来很笨拙且重复。有更简单的方法吗?Displaymy_fmt()

这是一个完整的示例程序来说明这一点。它比我想要的要长一点(它基于我之前的问题Calling functions that return different types with Shared Trait and pass to other function 的答案),但我想不出更简单的方法来说明这一点。当然,在这个玩具示例中,结构和fmt函数非常简单;在我的实际应用中它们更加复杂。

use std::fmt;

trait MyTrait {
    fn is_even(&self) -> bool;
    fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
}

struct First {
    v: u8,
}

struct Second {
    v: Vec<u8>,
}

impl MyTrait for First {
    fn is_even(&self) -> bool {
        self.v % 2 == 0
    }

    fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.v)
    }
}

impl MyTrait for Second {
    fn is_even(&self) -> bool {
        self.v[0] % 2 == 0
    }

    fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.v[0])
    }
}

fn make1() -> First {
    First { v: 5 }
}

fn make2() -> Second {
    Second { v: vec![2, 3, 5] }
}

// Implement Display for the structs and for MyTrait
impl fmt::Display for First {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.v)
    }
}

impl fmt::Display for Second {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.v[0])
    }
}

impl fmt::Display for MyTrait {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.my_fmt(f)
    }
}

fn requires_mytrait<T: MyTrait + ?Sized>(v: &&T) {
    println!("{:?}", v.is_even());
}

fn main() {
    for i in 0..2 {
        let v1;
        let v2;
        let v = match i {
            0 => {
                v1 = make1();
                println!("> {}", v1); // Demonstrate that Display
                                      // is implemented directly
                                      // on the type.
                &v1 as &MyTrait
            }
            _ => {
                v2 = make2();
                println!("> {}", v2); // Demonstrate that Display
                                      // is implemented directly
                                      // on the type.
                &v2 as &MyTrait
            }
        };
        requires_mytrait(&v);
        println!("{}", v); // Here I print the trait object
    }
}
Run Code Online (Sandbox Code Playgroud)

谁能建议一种更简单、更干净的方法来做到这一点?

Jay*_*epp 8

你可以创造Display一个超级特质MyTrait

trait MyTrait: fmt::Display {
    fn is_even(&self) -> bool;
}
Run Code Online (Sandbox Code Playgroud)

这将使特征对象成为MyTraitbe Display。仅当您希望 的所有实现者都MyTrait实现 时,这才有效Display,但您之前的解决方案也是如此。