如何在类型已经实现 Display 的 trait 对象上实现 Display [英] How to implement Display on a trait object where the types already implement Display

查看:27
本文介绍了如何在类型已经实现 Display 的 trait 对象上实现 Display的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have some code which returns a trait object of type MyTrait so that it can return one of several different structs. I would like to implement the Display trait for the trait object so that I can print the object, with the details delegated to the various structs as they each need their own custom formatters.

我可以通过在 MyTrait 定义中包含格式化方法来实现这一点,然后为 MyTrait 实现 Display 并委托 - 就像这个:

I can achieve this by including a formatting method as part of the MyTrait definition, and then implementing Display for MyTrait and delegating - like this:

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)
    }
}

但是,我已经为实现 MyTrait 的每个结构实现了 Display 特征.这意味着我最终为每个结构体使用了两个方法,它们做同样的事情 - fmt() 方法直接在结构体上满足 Display 特性,而 fmt()>my_fmt() 方法由上面的代码调用.这看起来很笨拙和重复.有没有更简单的方法?

However, I already have the Display trait implemented for each of the structs which implement MyTrait. This means I end up with two methods for each struct which do the same thing - the fmt() method to satisfy the Display trait directly on the struct, and the my_fmt() method which is called by the code above. This seems clumsy and repetitions. Is there a simpler way to do it?

这是一个完整的示例程序,它说明了这一点.它比我希望的要长一点(它基于对我上一个问题的回答 调用返回具有共享特征的不同类型并传递给其他函数的函数,但我想不出更简单的方法来说明这一点.当然,在这个玩具示例中,结构体和 fmt 函数非常简单,但在我的实际应用中它们更复杂.

Here's a complete example program which illustrates the point. It's a little longer than I would have liked (it's based on the answer to my previous question Calling functions which return different types with shared trait and pass to other functions but I couldn't think of a simpler way to illustrate the point. Of course, in this toy example the structs and the fmt functions are very simple, but in my real application they are more complex.

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
    }
}

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

Can anyone suggest a simpler, cleaner way to do this?

推荐答案

您可以使 Display 成为 MyTrait 的超特征.

You can make Display a supertrait of MyTrait.

trait MyTrait: fmt::Display {
    fn is_even(&self) -> bool;
}

这将使 MyTrait 的 trait 对象成为 Display.这仅在您希望 MyTrait 的所有实现者都实现 Display 时才有效,但在您之前的解决方案中也是如此.

This will make trait objects of MyTrait be Display. This only works if you expect all implementors of MyTrait to implement Display, but that was also the case in your previous solution.

这篇关于如何在类型已经实现 Display 的 trait 对象上实现 Display的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆