我正在努力了解如何正确实现结构的任何类型的替代显示或特征。
struct Fraction {
numerator: u32,
denominator: u32
}
impl Fraction {
fn unicode(&self) -> impl Display {
// should I use named function or Closure?
// Where does f come from?
// can I re-use self?
// How can I implement a trait that has multiple required functions or `type Output =`?
fn fmt(&self, f: std::fmt::Formatter) -> std::fmt::Result {
write!("{}⁄{}", self.numerator, self.denominator)
} // <- this returns `()`
}
}
这是行不通的,因为fn fmt
作为函数定义,不会返回任何内容。使用未命名的闭包:
impl Fraction {
fn unicode(&self) -> impl Display {
// should I use named function or Closure?
// Where does f come from?
// can I re-use self?
// How can I implement a trait that has multiple required functions or `type Output =`?
|s: &Self, f: std::fmt::Formatter| -> std::fmt::Result {
write!("{}⁄{}", self.numerator, self.denominator)
} // <- this returns `()`
}
}
// somewhere else:
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
类似问题:
与返回迭代器(我发现的大多数文档都是关于此的)相反,我试图在函数块中实现我的特征。因此我找不到文档。也许这是错误的做法/思考方式?
正如 @cafce25 在评论中指出的那样,您必须返回实现该特征的东西,这在 Rust 中意味着您需要有一个实现该特征的类型的实例。但您仍然可以从签名和导出类型中“隐藏”这一点,例如通过在函数中声明类型:
返回的实例必须携带足够的数据,以便其
Display
实现能够实际运行。在Example
上面,没有数据(Example
实际上是ZST),因为fmt
实现只是将常量字符串写入格式化程序。但更现实的是,您将需要一些实施数据,例如
Fraction
:如果您想避免克隆并仅通过共享引用捕获原始部分(因为生成的对象只需要在打印调用期间存在),您可以这样做:
在这里,我们声明了返回的“隐藏”对象的生命周期(即赋予函数
'a
的原始引用的生命周期),我们也必须在块中拼写出来。这是带有引用的结构的标准。有点令人惊讶的是返回类型中添加了额外的内容。如果没有这个,编译器会抱怨:“捕获未出现在边界内的生命周期的隐藏类型”。也就是说,即使我们实际上没有在签名中说明生命周期,但返回实例的生命周期与原始实例的生命周期之间存在联系,即返回实例的生命周期不能比原始实例的生命周期长。Fraction
unicode
impl
+ '_
impl std::fmt::Display
unicode
Fraction
对您在评论中提出的问题的简短回答:
-> impl Iterator<Item = i32>
?由于您必须有一个完整的impl
特征块,因此您可以像往常一样声明所有函数和关联的类型。self
吗?不,如上所示,您需要捕获引用、克隆数据或将所需的一些数据提取到返回的实例中。最后,让我指出这
-> impl SomeTrait
并不意味着该函数返回一个特征对象(如-> Box<dyn SomeTrait>
)。例如,该函数不能从不同分支返回不同的实现SomeTrait
。该语法仅意味着存在一个实现该特征的类型,但您不会从签名中看到该类型。