Можно ли определить, является ли поле определенного типа или реализует определенный метод в процедурном макросе?
Нет, это не так.
Макросыработать с абстрактным синтаксическим деревом (AST) кода Rust.Это означает, что вы в основном просто получаете символы, которые набрал пользователь.
Если код пользователя имеет что-то вроде type Foo = Option<Result<i32, MyError>>
, и вы обрабатываете некоторый код, который использует Foo
, макрос не будет знать, что это "на самом деле Option
.
Даже если бы он знал тип, знать, какие методы доступны, было бы еще сложнее.Будущие ящики могут создавать черты, которые добавляют методы к существующим типам.В тот момент, когда выполняется процедурный макрос, эти ящики, возможно, еще даже не были скомпилированы.
Я смотрю на создание другой функции trait / member, которую мне просто нужно создать для всех примитивов.и создайте процедурный макрос для больших полей, таких как структуры.
Это правильное решение.Если вы посмотрите на любой хорошо используемый процедурный макрос, это именно то, что он делает.Это позволяет компилятору делать то, для чего предназначен компилятор.
Это также намного лучше для удобства сопровождения - теперь эти примитивные реализации живут в стандартном файле 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);
ToBytes::encode(&self.b);
}
}
В качестве конкретного примера, Serde делает то же самое с множественными способами сериализации в двоичные данные и из них: