如何从Rust函数返回`impl Display`类型?
如何为结构体实现替代Display的自定义格式化方式?
我搞不懂怎么给结构体正确实现替代Display的自定义Trait,或者说怎么返回一个实现了Display的类型来做不同的格式化输出。比如我定义了Fraction结构体,已经给它实现了默认的Display(用ASCII的/),现在想加一个方法返回用Unicode分号⁄的显示方式,但试了两种写法都不行。
第一种错误尝试:内部函数
struct Fraction { numerator: u32, denominator: u32 } impl Fraction { fn unicode(&self) -> impl Display { // 疑问:我应该用命名函数还是闭包? // 参数f是哪来的? // 能不能复用self? // 怎么实现带多个必要方法或者有`type Output =`的Trait? fn fmt(&self, f: std::fmt::Formatter) -> std::fmt::Result { write!("{}⁄{}", self.numerator, self.denominator) } // <- 这里返回的是()` } }
这种写法无效,因为内部的fmt函数只是被定义,并没有返回一个实现了Display的类型。
第二种错误尝试:闭包
impl Fraction { fn unicode(&self) -> impl Display { // 疑问:我应该用命名函数还是闭包? // 参数f是哪来的? // 能不能复用self? // 怎么实现带多个必要方法或者有`type Output =`的Trait? |s: &Self, f: std::fmt::Formatter| -> std::fmt::Result { write!("{}⁄{}", self.numerator, self.denominator) } // <- 这里返回的是()` } } // 已实现的默认Display impl Display for Fraction { fn fmt(&self, f: std::fmt::Formatter) -> std::fmt::Result { write!("{}/{}", self.numerator, self.denominator) // ^-- ASCII '/' } }
运行后出现如下错误:
error[E0277]: `{closure@src/fraction/generic_fraction.rs:422:9: 422:57}` doesn't implement `std::fmt::Display` --> src/fraction/generic_fraction.rs:418:39 | 418 | fn display_mixed<'a>(&'a self) -> impl 'a + fmt::Display | ^^^^^^^^^^^^^^^^^^^^^^ `{closure@src/fraction/generic_fraction.rs:422:9: 422:57}` cannot be formatted with the default formatter | = help: the trait `std::fmt::Display` is not implemented for closure `{closure@src/fraction/generic_fraction.rs:422:9: 422:57}` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
正确解决方法
闭包或内部函数本身并没有实现Display trait,所以不能直接返回它们。正确的做法是定义一个辅助结构体,持有原结构体的引用,然后给这个辅助结构体实现Display,最后让方法返回该结构体。
示例代码
use std::fmt; struct Fraction { numerator: u32, denominator: u32, } // 定义辅助结构体,用于Unicode格式的显示 struct UnicodeFraction<'a>(&'a Fraction); // 给辅助结构体实现Display impl<'a> fmt::Display for UnicodeFraction<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}⁄{}", self.0.numerator, self.0.denominator) } } impl Fraction { fn unicode(&self) -> impl fmt::Display + '_ { UnicodeFraction(self) } } // 默认的Display实现 impl fmt::Display for Fraction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}/{}", self.numerator, self.denominator) } } // 测试使用 fn main() { let frac = Fraction { numerator: 1, denominator: 2 }; println!("默认格式: {}", frac); // 输出 1/2 println!("Unicode格式: {}", frac.unicode()); // 输出 1⁄2 }
关键点说明
- 辅助结构体
UnicodeFraction持有Fraction的引用,生命周期'a确保引用不会悬空,同时复用原结构体的字段。 - 给辅助结构体单独实现
Display,自定义格式化逻辑,与原结构体的Display实现互不干扰。 unicode方法返回该辅助结构体,因为它实现了Display,所以可以直接用于格式化字符串。
如果需要处理更复杂的Trait(比如带关联类型或多个方法的Trait),思路完全一致:定义适配类型,持有原数据的引用或所有权,然后在适配类型上实现目标Trait。
内容的提问来源于stack exchange,提问作者Fee
相关产品推荐
相关产品推荐

