有没有一种方法可以做到这一点,而无需每次使用模式匹配提取它们的“内部”值,也无需实现 Add、Sub、... 特征和重载运算符?
不,唯一的方法是手动实现特征。 Rust 没有与 the Haskell's GHC extension 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 for Centimeters,您会发现这些宏调用以及普通的 impls。
如果您经常访问 Centimeters 类型的内容,您可以考虑使用带有字段的适当结构来定义包装器:
struct Centimeters { amt: i32 }
这允许您编写self.amt 而不必进行模式匹配。您还可以定义一个类似fn cm(x: i32) -> Centimeters { Centimeters { amt: x } } 的函数,调用类似cm(100),以避免构建完整结构的冗长。
您还可以使用.0、.1 语法访问元组结构的内部值。