是否可以自动定义结构的字段?
Is it possible to automatically define fields of a struct?
我正在使用一个宏来实现一个特征作为我的库的一部分。此实现要求结构至少有一个附加字段。
pub trait Trait {
fn access_var(&mut self, var: bool);
}
macro_rules! impl_trait {
(for $struct:ident) => {
impl Trait for $struct {
pub fn access_var(&mut self, var: bool) {
self.var = var; // requires self to have a field 'var'
}
}
}
}
我想避免用户每次都必须添加这些附加字段。由于 Rust 编译器不允许在字段定义中使用宏(我没有这方面的来源,所以如果我错了请纠正我),这样的事情是行不通的。
macro_rules! variables_for_trait {
() => {
var: bool,
}
};
struct Foo {
variables_for_trait!(); // error: expected ':' found '!'
additional_var: i64,
}
我想我可以创建一个宏来实现这样的功能
bar!(Foo with additional_var: i64, other_var: u64);
解析宏后的样子:
pub struct Foo {
var: bool,
additional_var: i64,
other_var: u64,
}
impl Trait for Foo {
pub fn access_var(&mut self, var: bool) {
self.var = var;
}
}
有没有更好的方法来解决这个问题,如果没有,你能给我一个 bar!
的示例语法吗?
P.S: 给 bar!
这样的东西起什么名字比较好?
我最终用 2 个不同的宏解决了这个问题:
// I simply copied it from my project and changed some names,
// But due to the fact that I couldn't think of better names for my macros,
// I just ended up using the original names, even though they don't quite fit
macro_rules! new_object_type {
($struct:ident {$( $field:ident:$type:ty ),*}) =>{
pub struct $struct {
var: bool,
$(
$field: $type,
)*
}
impl Trait for $struct {
pub fn access_var(&mut self, var: bool) {
self.var = var;
}
}
};
}
macro_rules! construct_object {
($struct:ident {$( $field:ident:$value:expr ),*}) => {
$struct {
var: false,
$(
$field: $value,
)*
}
};
}
要创建一个实现 Trait
的新结构,您现在要编写:
new_object_type!(Foo {
additional_var: i64,
other_var: u64,
});
并创建一个 Foo
的新实例,你写:
construct_object!(Foo {
additional_var: 42,
other_var: 82000,
})
现在可以使用 Trait
而无需与 var
交互。
这种方法的问题:
它不像我希望的那样干净,没有适当的文档很难使用,特别是如果用户是 Rust 的新手。
有两个相同的字段可能会出现一些问题,因为用户看不到所有已实现的变量(这可以通过将 var 的名称更改为 T7dkD3S3O8
之类的名称来解决肯定会使这种情况不太可能发生)
由于结构的定义和构造都在宏中,错误消息可能更难理解
我正在使用一个宏来实现一个特征作为我的库的一部分。此实现要求结构至少有一个附加字段。
pub trait Trait {
fn access_var(&mut self, var: bool);
}
macro_rules! impl_trait {
(for $struct:ident) => {
impl Trait for $struct {
pub fn access_var(&mut self, var: bool) {
self.var = var; // requires self to have a field 'var'
}
}
}
}
我想避免用户每次都必须添加这些附加字段。由于 Rust 编译器不允许在字段定义中使用宏(我没有这方面的来源,所以如果我错了请纠正我),这样的事情是行不通的。
macro_rules! variables_for_trait {
() => {
var: bool,
}
};
struct Foo {
variables_for_trait!(); // error: expected ':' found '!'
additional_var: i64,
}
我想我可以创建一个宏来实现这样的功能
bar!(Foo with additional_var: i64, other_var: u64);
解析宏后的样子:
pub struct Foo {
var: bool,
additional_var: i64,
other_var: u64,
}
impl Trait for Foo {
pub fn access_var(&mut self, var: bool) {
self.var = var;
}
}
有没有更好的方法来解决这个问题,如果没有,你能给我一个 bar!
的示例语法吗?
P.S: 给 bar!
这样的东西起什么名字比较好?
我最终用 2 个不同的宏解决了这个问题:
// I simply copied it from my project and changed some names,
// But due to the fact that I couldn't think of better names for my macros,
// I just ended up using the original names, even though they don't quite fit
macro_rules! new_object_type {
($struct:ident {$( $field:ident:$type:ty ),*}) =>{
pub struct $struct {
var: bool,
$(
$field: $type,
)*
}
impl Trait for $struct {
pub fn access_var(&mut self, var: bool) {
self.var = var;
}
}
};
}
macro_rules! construct_object {
($struct:ident {$( $field:ident:$value:expr ),*}) => {
$struct {
var: false,
$(
$field: $value,
)*
}
};
}
要创建一个实现 Trait
的新结构,您现在要编写:
new_object_type!(Foo {
additional_var: i64,
other_var: u64,
});
并创建一个 Foo
的新实例,你写:
construct_object!(Foo {
additional_var: 42,
other_var: 82000,
})
现在可以使用 Trait
而无需与 var
交互。
这种方法的问题:
它不像我希望的那样干净,没有适当的文档很难使用,特别是如果用户是 Rust 的新手。
有两个相同的字段可能会出现一些问题,因为用户看不到所有已实现的变量(这可以通过将 var 的名称更改为
T7dkD3S3O8
之类的名称来解决肯定会使这种情况不太可能发生)由于结构的定义和构造都在宏中,错误消息可能更难理解