有没有一种方法可以做到这一点,而无需每次都通过模式匹配提取其“内部”值,并且无需实现 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
你会发现这些宏调用以及正常的调用impl
s.
如果您正在访问的内容Centimeters
输入很多,您可以考虑使用带有字段的适当结构来定义包装器:
struct Centimeters { amt: i32 }
这允许你写self.amt
而不必进行模式匹配。您还可以定义一个函数,例如fn cm(x: i32) -> Centimeters { Centimeters { amt: x } }
,称为像cm(100)
,以避免构造完整结构的冗长。
您还可以使用以下命令访问元组结构的内部值.0
, .1
syntax.