【问题标题】:Is it possible to write chained comparison macro in Rust?是否可以在 Rust 中编写链式比较宏?
【发布时间】:2020-01-28 05:52:54
【问题描述】:

在 rust 中,只要参数是 idents,就可以在宏参数中传递 ><= 等。

是否可以创建一个让您链接比较运算符的宏?

let x = 3;
let y = 1;
let z = -3;

assert_eq!(cond!(z <= x > y), true);

【问题讨论】:

    标签: rust macros


    【解决方案1】:

    是的,你可以。运算符类型需要使用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));
    }
    

    Playground

    您还可以阅读The little book of Rust Macros 了解更高级的宏模式。

    【讨论】:

    • 这确实允许一些可能有问题的奇怪结构,例如cond!(x+y)。但它肯定是短而整洁的。
    【解决方案2】:

    我认为,只要您小心 cond 的参数,以下内容就可以满足您的期望

    它使用tt(用于参数operator0)来匹配&lt;&lt;=&gt;=等,以避免重复很多情况,但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);
    }
    

    【讨论】:

      【解决方案3】:

      我认为这在技术上是可行的,但我不确定我是否会亲自去做。 要处理所有运算符而不匹配某些不应该工作的东西,例如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));
      }
      
      

      【讨论】:

      • 也许您可以修改您的示例以支持变量比较运算符。
      猜你喜欢
      • 2012-11-07
      • 2018-11-05
      • 1970-01-01
      • 1970-01-01
      • 2020-03-23
      • 1970-01-01
      • 1970-01-01
      • 2014-05-28
      • 2019-03-25
      相关资源
      最近更新 更多