我想写一个像这样的宏:
macro_rules! a {
( $n:ident, $t:ty ) => {
struct $n {
x: $t
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是$t应该实现Add,Sub和Mul特征.如何在编译时检查它?
首先,解决没有宏的问题.一种解决方案是创建未记录的私有函数,如果不满足条件,将无法编译:
struct MyType {
age: i32,
name: String,
}
fn __assert_send()
where
MyType: Send,
{}
fn __assert_sync()
where
MyType: Sync,
{}
// RFC 2056
fn __assert_traits() {
__assert_send();
__assert_sync();
}
Run Code Online (Sandbox Code Playgroud)
然后,修改简单的解决方案以使用宏:
macro_rules! a {
($n:ident, $t:ty) => {
struct $n {
x: $t
}
impl $n {
fn __assert_add()
where
$t: std::ops::Add<$t, Output = $t>
{}
fn __assert_mul()
where
$t: std::ops::Mul<$t, Output = $t>
{}
// RFC 2056
fn __assert_traits() {
Self::__assert_add();
Self::__assert_mul();
}
}
}
}
a!(Moo, u8);
a!(Woof, bool);
fn main() {}
Run Code Online (Sandbox Code Playgroud)
然后我会相信优化器在编译时删除代码,所以我不希望任何额外的膨胀.
主要得益于以克里斯·摩根提供一个更好的版本的这种支持非对象的安全特性.
值得强调的是RFC 2056,它允许where子句中的"琐碎"约束.一旦实施,将接受这样的条款:
impl Foo for Bar
where
i32: Iterator,
{}
Run Code Online (Sandbox Code Playgroud)
在Rust的历史记录中,这种确切的行为已经多次改变,而RFC 2056则将其固定下来.为了在这种情况下保持我们想要的行为,我们需要从没有约束的另一个函数调用断言函数(因此必须始终为true).