Generics 如何匹配泛型结构字段的具体类型?
我在玩lambda演算,但由于我对泛型不太了解,我想确认一下我对某些事情的理解,并解决一个错误。考虑以下定义:Generics 如何匹配泛型结构字段的具体类型?,generics,rust,Generics,Rust,我在玩lambda演算,但由于我对泛型不太了解,我想确认一下我对某些事情的理解,并解决一个错误。考虑以下定义: pub trait Term {} // a lambda term - a variable, an abstraction or an application pub struct Var(pub usize); // a variable, De Bruijn style pub struct Abs<T: Term>(T); // an abstraction p
pub trait Term {} // a lambda term - a variable, an abstraction or an application
pub struct Var(pub usize); // a variable, De Bruijn style
pub struct Abs<T: Term>(T); // an abstraction
pub struct App<T: Term, U: Term>(T, U); // application of T on U
有趣的是,我在这里不需要App
,但希望到目前为止一切顺利-现在我想为上述结构实现fmt::Display
:
use std::fmt;
use std::fmt::Display;
impl fmt::Display for Var {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl<T: Term+Display> Display for Abs<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "λ{}", self.0)
}
}
但它在以下方面失败了:
错误[E0308]:类型不匹配
-->src\ast.rs:34:8
|
34 |应用程序(Var(|),Var(|))=>写入!(f,“{}{}”,self.0,self.1),
|^应为类型参数,找到结构'ast::Var'`
|
=注意:应为'T'类型`
=注意:找到类型`ast::Var`
我想根据其内容的类型以不同的方式打印App
。我试图找到一个相关的问题,但它们大多围绕着相关的类型。是否有一个简单的解决方案,或者我必须修改定义
我想根据其内容的类型以不同的方式打印App
这很简单,只需为您希望能够打印的每种独特类型的应用程序实现显示
:
use std::fmt;
struct App<T, U>(T, U);
impl fmt::Display for App<i32, bool> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Awesome choice!")
}
}
impl fmt::Display for App<bool, String> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Woah, a string? Really?")
}
}
fn main() {
println!("{}", App(42i32, false));
println!("{}", App(true, "wow".to_string()));
}
这在标准库中有一个近似的模拟:。此类型接受泛型,但所有有趣的功能仅针对少数具体类型实现,如&[u8]
或Vec
但是它仍然会导致问题,例如,对于App
,因为内部App
需要再次使用2个类型参数
是的,您必须指定泛型,因为App
不是一种类型,它只是迈向一种类型的垫脚石
这完全取决于你想做什么。最简单的方法是让应用程序
由两种类型的应用程序组成,只要您不使用它们:
impl<T, U> fmt::Display for App<i32, App<T, U>> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Semi-awesome")
}
}
请与我们联系
fn main() {
let a = App(42i32, false);
println!("{}", a);
let b = App(100, a);
println!("{}", b);
let c = App(100, b);
println!("{}", c);
}
我有一个猜测,接下来的问题将是关于所有非特殊条件的某种回退或默认情况。比如:
impl fmt::Display for App<i32, bool> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Awesome choice!")
}
}
impl<T: fmt::Display, U: fmt::Display> fmt::Display for App<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Boring: {} + {}", self.0, self.1)
}
}
impl fmt::应用程序的显示{
fn fmt(&self,f:&mut fmt::Formatter)->fmt::Result{
写!(f,“很棒的选择!”)
}
}
impl fmt::应用程序的显示{
fn fmt(&self,f:&mut fmt::Formatter)->fmt::Result{
写!(f,“无聊:{}+{}”,self.0,self.1)
}
}
不,那不会编译的i32和bool
也实现了Display
,因此选择哪个实现是不明确的。在这一点上,你是进入的领域。这迫使您真正理解孤儿规则
据我所知,专业化的当前实现方式,你不能专门化具体类型,只能专注于特征。有趣的是,我不需要App
在这里-这是因为你说Term
只有在App
的两个孩子都是同一类型时才能实现<代码>应用程序
是可以的,应用程序
不会。这意味着我确实需要它-我可能还没有触发错误,但我希望应用程序
的不同变体也是术语
s。我想知道几个单独的实现,但它仍然会带来麻烦,例如应用程序
,因为内部的App
再次需要2个类型参数-有什么办法吗?
impl<T, U> fmt::Display for App<i32, App<T, U>> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Semi-awesome")
}
}
impl<T, U> fmt::Display for App<i32, App<T, U>>
where App<T, U>: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}) squared!", self.1)
}
}
fn main() {
let a = App(42i32, false);
println!("{}", a);
let b = App(100, a);
println!("{}", b);
let c = App(100, b);
println!("{}", c);
}
impl fmt::Display for App<i32, bool> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Awesome choice!")
}
}
impl<T: fmt::Display, U: fmt::Display> fmt::Display for App<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Boring: {} + {}", self.0, self.1)
}
}