我可以在结构体内部调用宏吗?

时间:2020-08-28 15:22:57

标签: rust rust-macros

我对Rust还是比较陌生,我正在使用宏进行锻炼。

目标是在Rust lang中归档某种React-ish语法。

我知道像jsx!(<div />)这样的DSL急剧使用方法,这是一个很好的解决方案,但它涉及另一个主题。我正在寻找中间的东西,更像是Flutter或SwiftUI语法,该语法尽可能地利用了本机语言功能,但仍然呈现了直观的分层代码结构。

在这里,我正在探索使用View宏构造children!结构的想法。

我的主要目的是启用View.children字段来保存任意Arity元组。由于可变参数通用元组在Rust中尚不可用,因此宏似乎是唯一的选择。

查看代码和注释:

struct View<T> {
  // children field holds arbitrary nullable data
  // but what i really want is Variadic Tuple, sadly not available in rust
  children: Option<T>,
}

// `children!` macro is a shorthand for Some(VariadicTuple)
// so to avoid the ugly `Some((...))` double parens syntax.
macro_rules! children {
  ($($x:expr),+ $(,)?) => (
    Some(($($x),*))
  );
}

fn main() {
  let _view = View {
    children: children!(
      42,
      "Im A String",
      View {
        children: Some(("foo", "bar")),
      },
    ),
  };
}

到目前为止一切顺利。现在,这是我真正想要进一步优化的最后一部分:

View { 孩子: children!(...) }

是否可以在结构体内部调用宏(而不是在value语法之后的field:位置),从而消除了冗余写入children:字段的需要?

1 个答案:

答案 0 :(得分:2)

是,不是。您不能完全按照自己的描述创建某些东西,但是可以做非常非常相似的事情。

您可以像这样为View结构实现new函数:

struct View<T> {
  // children field holds arbitrary Option<data>.
  children: Option<T>,
}

impl<T> View<T> {
  pub fn new() -> Self {
    Self {
      children: children!(
      42,
      "Im A String",
      View {
        children: Some(("foo", "bar")),
      },
    )
    }
  }
}

// `children!` macro is a shorthand for Some(VariadicTuple)
// so to avoid the ugly `Some((...))` double parens syntax.
macro_rules! children {
  ($($x:expr),+ $(,)?) => (
    Some(($($x),*))
  );
}

然后创建一个视图对象:

fn main() {
  let _view1 = View::new();
  let _view2 = View::new();
  let _view3 = View::new();

  // _view1, _view2, and _view3 are *exactly* the same
}

或者,如果您想添加参数,则对用例进行如下修改:

struct View<T> {
  // children field holds arbitrary Option<data>.
  children: Option<T>,
}

impl<T> View<T> {
  pub fn new(age: i32, string: &str) -> Self {
    Self {
      children: children!(
      age,
      string,
      View {
        children: Some(("foo", "bar")),
      },
    )
    }
  }
}

// `children!` macro is a shorthand for Some(VariadicTuple)
// so to avoid the ugly `Some((...))` double parens syntax.
macro_rules! children {
  ($($x:expr),+ $(,)?) => (
    Some(($($x),*))
  );
}

然后实现它:

fn main() {
  let _view1 = View::new(42, "Im A String");
  let _view2 = View::new(35, "Im another string");
  let _view3 = View::new(12, "This is yet another string");

  // _view1, _view2, and _view3 are *not* the same because they have differing "age" and "string" attributes.
}

如果这不是您想要的,或者想要更多帮助,我会在这里提供帮助。