gpt4 book ai didi

generics - 如何匹配具体类型的通用结构字段?

转载 作者:行者123 更新时间:2023-11-29 08:16:23 26 4
gpt4 key购买 nike

我正在研究 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
pub struct App<T: Term, U: Term>(T, U); // application of T on U

我明白(即,否则它不起作用)我需要 App<T: Term, U: Term> 上通用而不仅仅是 <T: Term>能够例如申请VarApp ,即有一个 App(Var(x), App(...)) .

上述结构都是Term小号:

impl Term for Var {}
impl<T: Term> Term for Abs<T> {}
impl<T: Term> Term for App<T, T> {}

有趣的是我不需要 App<T, U>在这里,但希望到目前为止一切顺利 - 现在我想实现 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)
}
}

这两个impl工作得很好;我将它们包括在内,因为下一个依赖于它们:

impl<T: Term+Display> Display for App<T, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
App(Var(_), Var(_)) => write!(f, "{}{}", self.0, self.1),
_ => unimplemented!()
}
}
}

但它失败了:

error[E0308]: mismatched types
--> src\ast.rs:34:8
|
34 | App(Var(_), Var(_)) => write!(f, "{}{}", self.0, self.1),
| ^^^^^^ expected type parameter, found struct `ast::Var`
|
= note: expected type `T`
= note: found type `ast::Var`

我想打印 App根据其内容的类型不同。我试图找到一个相关的问题,但它们主要围绕关联类型展开。是否有简单的解决方案,还是我必须重新定义定义?

最佳答案

I would like to print App differently based on the types of its contents.

这很简单,只需实现 Display对于每种独特类型的 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()));
}

您还可以接受具有自己泛型的其他类型:

impl<T> fmt::Display for App<Vec<T>, char> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} of them; {}", self.0.len(), self.1)
}
}

请注意,这没有 unimplemented!称呼;一切都在编译时检查:

error[E0277]: the trait bound `App<bool, bool>: std::fmt::Display` is not satisfied
--> src/main.rs:24:24
|
24 | println!("{}", App(true, false));
| ^^^^^^^^^^^^^^^^ the trait `std::fmt::Display` is not implemented for `App<bool, bool>`
|
= note: `App<bool, bool>` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
= note: required by `std::fmt::Display::fmt`

这在标准库中有一个相似的类比: Cursor .此类型接受泛型,但所有有趣的功能仅针对少数具体类型实现,如 &[u8]Vec<u8> .

but it still causes trouble, e.g. with App<Var, App>, because the inner App expects 2 type arguments again

是的,你必须指定泛型,因为 App 不是一种类型,它只是通向一个类型的垫脚石。

这完全取决于你想做什么。最简单的就是有一个 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")
}
}

如果你希望能够显示App , 那么你需要限制泛型使得 App可显示:

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

不,那不会编译! i32bool 同时实现Display 所以选择哪个实现是不明确的。此时,您进入了 specialization 的领域.这迫使您真正理解孤儿规则

据我了解当前的特化实现,您不能专注于具体类型,只能专注于特征。

关于generics - 如何匹配具体类型的通用结构字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42794578/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com