自动实现 Rust 新类型(具有一个字段的元组结构)的封闭类型的特征

2023-11-23

在 Rust 中,可以创建只有一个字段的元组结构,如下所示:

struct Centimeters(i32);

我想做基本算术Centimeters无需每次通过模式匹配提取它们的“内部”值,也无需实现Add, Sub, ... 特征和重载运算符。

我想做的是:

let a = Centimeters(100);
let b = Centimeters(200);
assert_eq!(a + a, b);

有没有一种方法可以做到这一点,而无需每次都通过模式匹配提取其“内部”值,并且无需实现 Add、Sub、... 特征和重载运算符?

不,唯一的方法是手动实现特征。 Rust 没有等价物Haskell 的 GHC 扩展GeneralizedNewtypeDeriving这使得deriving在包装类型上自动实现包装类型实现的任何类型类/特征(并且使用 Rust 的当前设置#[derive]作为一个简单的 AST 转换,像 Haskell 一样实现它基本上是不可能的。)

要简化该过程,您可以使用宏:

use std::ops::{Add, Sub};

macro_rules! obvious_impl {
    (impl $trait_: ident for $type_: ident { fn $method: ident }) => {
        impl $trait_<$type_> for $type_ {
            type Output = $type_;

            fn $method(self, $type_(b): $type_) -> $type_ {
                let $type_(a) = self;
                $type_(a.$method(&b))
            }
        }
    }
}

#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
pub struct Centimeters(i32);

obvious_impl! { impl Add for Centimeters { fn add } }
obvious_impl! { impl Sub for Centimeters { fn sub } }

#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)]
pub struct Inches(i32);

obvious_impl! { impl Add for Inches { fn add } }
obvious_impl! { impl Sub for Inches { fn sub } }

fn main() {
    let a = Centimeters(100);
    let b = Centimeters(200);
    let c = Inches(10);
    let d = Inches(20);
    println!("{:?} {:?}", a + b, c + d); // Centimeters(300) Inches(30)
    // error:
    // a + c;
}

playpen

我模仿的是正常的impl宏中的语法,只需查看宏调用即可清楚地了解发生的情况(即减少查看宏定义的需要),并且还保持 Rust 的自然可搜索性:如果您正在寻找以下特征Centimeters只是 grep 为for Centimeters你会发现这些宏调用以及正常的调用impls.

如果您正在访问的内容Centimeters输入很多,您可以考虑使用带有字段的适当结构来定义包装器:

struct Centimeters { amt: i32 }

这允许你写self.amt而不必进行模式匹配。您还可以定义一个函数,例如fn cm(x: i32) -> Centimeters { Centimeters { amt: x } },称为像cm(100),以避免构造完整结构的冗长。

您还可以使用以下命令访问元组结构的内部值.0, .1 syntax.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自动实现 Rust 新类型(具有一个字段的元组结构)的封闭类型的特征 的相关文章

随机推荐