我对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:
字段的需要?
答案 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.
}
如果这不是您想要的,或者想要更多帮助,我会在这里提供帮助。