是否可以在 Rust 中编写链式比较宏?
Is it possible to write chained comparison macro in Rust?
在 Rust 中,只要参数是 ident
,就可以在宏参数中传递 >
或 <=
等。
是否可以创建一个宏来链接比较运算符?
let x = 3;
let y = 1;
let z = -3;
assert_eq!(cond!(z <= x > y), true);
我认为这在技术上是可行的,但我不确定我个人是否会这样做。
要处理所有运算符而不匹配某些不应该工作的东西,如 cond!(a + b)
、cond!(a)
或 cond!()
,我必须非常冗长,并使用递归宏。可能可以简化初始(非@recur
)的情况,但我担心做错会导致无限递归。
macro_rules! cond {
( @recur $x:ident ) => { true };
( @recur $x:ident < $y:ident $($tail:tt)* ) => { ($x < $y) && cond!( @recur $y $($tail)*) };
( @recur $x:ident > $y:ident $($tail:tt)* ) => { ($x > $y) && cond!( @recur $y $($tail)*) };
( @recur $x:ident <= $y:ident $($tail:tt)* ) => { ($x <= $y) && cond!( @recur $y $($tail)*) };
( @recur $x:ident >= $y:ident $($tail:tt)* ) => { ($x >= $y) && cond!( @recur $y $($tail)*) };
( @recur $x:ident == $y:ident $($tail:tt)* ) => { ($x == $y) && cond!( @recur $y $($tail)*) };
( $x:ident < $y:ident $($tail:tt)* ) => { ($x < $y) && cond!( @recur $y $($tail)*) };
( $x:ident > $y:ident $($tail:tt)* ) => { ($x > $y) && cond!( @recur $y $($tail)*) };
( $x:ident <= $y:ident $($tail:tt)* ) => { ($x <= $y) && cond!( @recur $y $($tail)*) };
( $x:ident >= $y:ident $($tail:tt)* ) => { ($x >= $y) && cond!( @recur $y $($tail)*) };
( $x:ident == $y:ident $($tail:tt)* ) => { ($x == $y) && cond!( @recur $y $($tail)*) };
}
fn main() {
let x = 3;
let y = 1;
let z = -3;
println!("(z <= x > y) = {}", cond!(z <= x > y));
}
我认为只要您小心 cond
.
的参数,下面的内容就符合您的预期
它使用tt
(对于参数operator0
)来匹配<
、<=
、>=
等以避免重复很多情况,但是 tt
当然也匹配其他标记。
macro_rules! cond{
($x:ident $operator0:tt $x0:ident) => {
($x $operator0 $x0)
};
($x:ident $operator0:tt $x0:ident $($operator1:tt $x1:ident)*) => {
($x $operator0 $x0) && cond!($x0 $($operator1 $x1)*)
};
}
fn main() {
let x = 3;
let y = 1;
let z = -3;
assert_eq!(cond!(z <= x > y), true);
}
是的,你可以。您需要使用 tt
作为运算符类型:
macro_rules! cond {
(@rec ($head:expr) $last:ident $op:tt $next:ident $($tail:tt)*) => {
cond!(@rec (($head) && ($last $op $next)) $next $($tail)*)
};
(@rec ($head:expr) $last:ident) => { $head };
($first:ident $op:tt $next:ident $($tail:tt)*) => {
cond!(@rec ($first $op $next) $next $($tail)*)
}
}
fn main() {
let x = 3;
let y = 1;
let z = -3;
println!("(z <= x > y) = {}", cond!(z <= x > y));
}
您还可以阅读 The little book of Rust Macros 以了解更高级的宏模式。
在 Rust 中,只要参数是 ident
,就可以在宏参数中传递 >
或 <=
等。
是否可以创建一个宏来链接比较运算符?
let x = 3;
let y = 1;
let z = -3;
assert_eq!(cond!(z <= x > y), true);
我认为这在技术上是可行的,但我不确定我个人是否会这样做。
要处理所有运算符而不匹配某些不应该工作的东西,如 cond!(a + b)
、cond!(a)
或 cond!()
,我必须非常冗长,并使用递归宏。可能可以简化初始(非@recur
)的情况,但我担心做错会导致无限递归。
macro_rules! cond {
( @recur $x:ident ) => { true };
( @recur $x:ident < $y:ident $($tail:tt)* ) => { ($x < $y) && cond!( @recur $y $($tail)*) };
( @recur $x:ident > $y:ident $($tail:tt)* ) => { ($x > $y) && cond!( @recur $y $($tail)*) };
( @recur $x:ident <= $y:ident $($tail:tt)* ) => { ($x <= $y) && cond!( @recur $y $($tail)*) };
( @recur $x:ident >= $y:ident $($tail:tt)* ) => { ($x >= $y) && cond!( @recur $y $($tail)*) };
( @recur $x:ident == $y:ident $($tail:tt)* ) => { ($x == $y) && cond!( @recur $y $($tail)*) };
( $x:ident < $y:ident $($tail:tt)* ) => { ($x < $y) && cond!( @recur $y $($tail)*) };
( $x:ident > $y:ident $($tail:tt)* ) => { ($x > $y) && cond!( @recur $y $($tail)*) };
( $x:ident <= $y:ident $($tail:tt)* ) => { ($x <= $y) && cond!( @recur $y $($tail)*) };
( $x:ident >= $y:ident $($tail:tt)* ) => { ($x >= $y) && cond!( @recur $y $($tail)*) };
( $x:ident == $y:ident $($tail:tt)* ) => { ($x == $y) && cond!( @recur $y $($tail)*) };
}
fn main() {
let x = 3;
let y = 1;
let z = -3;
println!("(z <= x > y) = {}", cond!(z <= x > y));
}
我认为只要您小心 cond
.
它使用tt
(对于参数operator0
)来匹配<
、<=
、>=
等以避免重复很多情况,但是 tt
当然也匹配其他标记。
macro_rules! cond{
($x:ident $operator0:tt $x0:ident) => {
($x $operator0 $x0)
};
($x:ident $operator0:tt $x0:ident $($operator1:tt $x1:ident)*) => {
($x $operator0 $x0) && cond!($x0 $($operator1 $x1)*)
};
}
fn main() {
let x = 3;
let y = 1;
let z = -3;
assert_eq!(cond!(z <= x > y), true);
}
是的,你可以。您需要使用 tt
作为运算符类型:
macro_rules! cond {
(@rec ($head:expr) $last:ident $op:tt $next:ident $($tail:tt)*) => {
cond!(@rec (($head) && ($last $op $next)) $next $($tail)*)
};
(@rec ($head:expr) $last:ident) => { $head };
($first:ident $op:tt $next:ident $($tail:tt)*) => {
cond!(@rec ($first $op $next) $next $($tail)*)
}
}
fn main() {
let x = 3;
let y = 1;
let z = -3;
println!("(z <= x > y) = {}", cond!(z <= x > y));
}
您还可以阅读 The little book of Rust Macros 以了解更高级的宏模式。