【问题标题】:How to implement fmt::Display on a generically-typed enum in Rust?如何在 Rust 中的泛型枚举上实现 fmt::Display?
【发布时间】:2017-03-30 09:30:43
【问题描述】:

我已经使用这个递归枚举实现了我的链表,但现在我想为它实现一个自定义显示格式

use std::fmt;

#[derive(Debug)]
enum List<A> {
    Empty,
    Cons(A, Box<List<A>>),
}

impl<T> fmt::Display for List<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            List::Empty => write!(f, "()"),
            List::Cons(x, ref xs) => write!(f, "({} {})", x, xs),  
        }
    }
}

错误

error[E0277]: the trait bound `T: std::fmt::Display` is not satisfied
  --> src/main.rs:13:59
   |
13 |             List::Cons(x, ref xs) => write!(f, "({} {})", x, xs),  
   |                                                           ^ the trait `std::fmt::Display` is not implemented for `T`
   |
   = help: consider adding a `where T: std::fmt::Display` bound
   = note: required by `std::fmt::Display::fmt`

如果重要的话,这是我的其余代码

fn cons<A>(x: A, xs: List<A>) -> List<A> {
    return List::Cons(x, Box::new(xs));
}

fn len<A>(xs: &List<A>) -> i32 {
    match *xs {
        List::Empty => 0,
        List::Cons(_, ref xs) => 1 + len(xs),
    }
}

fn map<A, B>(f: &Fn(&A) -> B, xs: &List<A>) -> List<B> {
    match *xs {
        List::Empty => List::Empty,
        List::Cons(ref x, ref xs) => cons(f(x), map(f, xs)),
    }
}

fn main() {
    let xs = cons(1, cons(2, cons(3, List::Empty)));
    println!("{}", xs);
    println!("{:?}", len(&xs));

    let f = |x: &i32| (*x) * (*x);
    let ys = map(&f, &xs);
    println!("{}", ys);
    println!("{}", List::Empty);
}

预期输出

(1 (2 (3 ())))
3
(1 (4 (9 ())))
()

真的我很想看到这个,但我完全不知道如何使用fmt::Result 获得这种输出

(1 2 3)
3
(1 4 9) 
()

【问题讨论】:

  • 我主要对解决这两个问题中的更简单感兴趣。如果我们能弄清楚后者的格式选项,那就是锦上添花。
  • 供将来参考:您的问题的确切原因和解决方案就在错误消息中。第一行告诉你T 缺少必要的约束,后面的注释建议你可以用什么形式来介绍它。
  • DK 事后看来是有道理的。但在看到公认的答案之前,我什至不知道这些东西是什么意思。不过你的评论很有帮助^^
  • 好吧,如果你运行它建议的命令(rustc --explain E0277),它会打印出更完整的解释和一个例子来告诉你它的含义。我提出这个只是为了确保你现在知道信息在那里。
  • 谢谢,我是认真的。我目前正在学习使用 repl.it/languages/rust buy 我明天会安装 rust - 承诺 ????

标签: enums formatting rust


【解决方案1】:

解决编译错误

你缺少一个特质绑定。也就是说,你需要告诉 Rust 可以显示T

impl<T: fmt::Display> fmt::Display for List<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            List::Empty => write!(f, "()"),
            List::Cons(ref x, ref xs) => write!(f, "({} {})", x, xs),  
        }
    }
}

注意特征绑定T: fmt::Display。这基本上意味着:如果T 实现fmt::Display,那么List&lt;T&gt; 也实现fmt::Display

锦上添花

我不确定您是否可以通过递归定义获得良好的格式。此外,Rust 不保证尾调用优化,因此总是存在堆栈溢出的可能性。

另一种定义可以是:

fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "(")?;
    let mut temp = self;
    while let List::Cons(ref x, ref xs) = *temp {
        write!(f, "{}", x)?;

        // Print trailing whitespace if there are more elements
        if let List::Cons(_, _) = **xs {
            write!(f, " ")?;
        }

        temp = xs;
    }

    write!(f, ")")
}

注意大多数write! 宏调用之后的?。它基本上意味着:如果这个write! 导致错误,现在返回错误。否则,继续执行函数。

【讨论】:

  • 另请注意,x 已更改为 ref x
  • 另一个有用的答案,aochagavia。想试试二级列表显示格式吗?
  • 刚刚为此写了一个函数:)
  • arigatou!你给了我很多有用的东西去思考!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多