是否可以判断一个字段是否是某种类型或在过程宏中实现某种方法?
Is it possible to tell if a field is a certain type or implements a certain method in a procedural macro?
我创建了一个实现特征的过程宏,但为了让它工作,我需要获取每个字段的原始字节。问题是如何获取字段的字节因字段类型而异。
是否有某种方法可以测试一个函数是否存在于一个字段上以及它是否不尝试另一个函数?
例如像这样:
if item.field::function_exist {
//do code
} else {
//do other code
}
目前我正在考虑创建另一个 trait/member 函数,我只需要为所有基元创建该函数并为更大的字段(例如结构)创建一个过程宏。例如:
if item.field::as_bytes().exists {
(&self.#index).as_bytes()
} else {
let bytes = (&self.#index).to_bytes();
&bytes
}
对于字符串,它有一个as_bytes
成员函数,而i32
则没有。这意味着当结构的成员字段不是字符串时,我需要额外的代码。我可能需要 match
而不是 if
,但是 if
就足够了。
Is it possible to tell if a field is a certain type or implements a certain method in a procedural macro?
不,不是。
宏对 Rust 代码的 abstract syntax tree (AST) 进行操作。这意味着您基本上只获取用户输入的字符。
如果用户代码有类似 type Foo = Option<Result<i32, MyError>>
的东西,而你处理一些使用 Foo
的代码,宏将不知道它“真的”是一个 Option
.
即使确实知道类型,知道可用的方法会更难。未来的板条箱可以创建特征,将方法添加到现有类型。在程序宏 运行 的时间点,这些 crates 可能还没有被编译。
I am looking at creating another trait/member function that I just have to create for all primitives and create a procedural macro for larger fields such as structs.
这是正确的解决方案。如果您查看任何现有的使用良好的程序宏,它就是这样做的。这允许编译器执行编译器打算执行的操作。
这对于可维护性来说也更好——现在这些原始实现存在于标准 Rust 文件中,而不是嵌入在宏中。更容易阅读和调试。
你的箱子里会有这样的东西:
// No real design put into this trait
trait ToBytes {
fn encode(&self, buf: &mut Vec<u8>);
}
impl ToBytes for str {
fn encode(&self, buf: &mut Vec<u8>) {
buf.extend(self.as_bytes())
}
}
// Other base implementations
您的程序宏将以直接的方式实现:
#[derive(ToBytes)]
struct Foo {
a: A,
b: B,
}
变成
impl ToBytes for Foo {
fn encode(&self, buf: &mut Vec<u8>) {
ToBytes::encode(&self.a, buf);
ToBytes::encode(&self.b, buf);
}
}
作为一个具体的例子,Serde做同样的事情,用多种序列化二进制数据的方式:
我创建了一个实现特征的过程宏,但为了让它工作,我需要获取每个字段的原始字节。问题是如何获取字段的字节因字段类型而异。
是否有某种方法可以测试一个函数是否存在于一个字段上以及它是否不尝试另一个函数?
例如像这样:
if item.field::function_exist {
//do code
} else {
//do other code
}
目前我正在考虑创建另一个 trait/member 函数,我只需要为所有基元创建该函数并为更大的字段(例如结构)创建一个过程宏。例如:
if item.field::as_bytes().exists {
(&self.#index).as_bytes()
} else {
let bytes = (&self.#index).to_bytes();
&bytes
}
对于字符串,它有一个as_bytes
成员函数,而i32
则没有。这意味着当结构的成员字段不是字符串时,我需要额外的代码。我可能需要 match
而不是 if
,但是 if
就足够了。
Is it possible to tell if a field is a certain type or implements a certain method in a procedural macro?
不,不是。
宏对 Rust 代码的 abstract syntax tree (AST) 进行操作。这意味着您基本上只获取用户输入的字符。
如果用户代码有类似 type Foo = Option<Result<i32, MyError>>
的东西,而你处理一些使用 Foo
的代码,宏将不知道它“真的”是一个 Option
.
即使确实知道类型,知道可用的方法会更难。未来的板条箱可以创建特征,将方法添加到现有类型。在程序宏 运行 的时间点,这些 crates 可能还没有被编译。
I am looking at creating another trait/member function that I just have to create for all primitives and create a procedural macro for larger fields such as structs.
这是正确的解决方案。如果您查看任何现有的使用良好的程序宏,它就是这样做的。这允许编译器执行编译器打算执行的操作。
这对于可维护性来说也更好——现在这些原始实现存在于标准 Rust 文件中,而不是嵌入在宏中。更容易阅读和调试。
你的箱子里会有这样的东西:
// No real design put into this trait
trait ToBytes {
fn encode(&self, buf: &mut Vec<u8>);
}
impl ToBytes for str {
fn encode(&self, buf: &mut Vec<u8>) {
buf.extend(self.as_bytes())
}
}
// Other base implementations
您的程序宏将以直接的方式实现:
#[derive(ToBytes)]
struct Foo {
a: A,
b: B,
}
变成
impl ToBytes for Foo {
fn encode(&self, buf: &mut Vec<u8>) {
ToBytes::encode(&self.a, buf);
ToBytes::encode(&self.b, buf);
}
}
作为一个具体的例子,Serde做同样的事情,用多种序列化二进制数据的方式: