文章详细介绍了 Rust 语言中的 attribute-like 和 custom derive 宏的使用方法,通过具体代码示例展示了如何通过宏在编译时修改结构体,并解释了宏的工作原理和实现方式。
Rust 中的类似属性和自定义派生宏用于在编译时以某种方式修改一段 Rust 代码,通常是为了增加功能。
要理解 Rust 中的类似属性和自定义派生宏,我们首先需要简要介绍 Rust 中的实现结构。
impl
以下结构应该是相当容易理解的。当我们创建对特定结构进行操作的函数时,事情就变得有趣了。我们这样做的方法是使用 impl
:
struct Person {
name: String,
age: u8,
}
关联函数和方法是在 impl
块中为结构实现的。
关联函数可以与 Solidity 中为与结构交互创建库的场景进行比较。当我们定义 using lib for MyStruct
时,它允许我们使用语法 myStruct.associatedFunction()
。这使得该函数可以通过 Self
关键字访问 myStruct
。
我们建议使用 Rust Playground,但对于更复杂的示例,你可能需要设置你的 IDE。
让我们看一个下面的示例:
struct Person {
age: u8,
name: String,
}
// 为 `Person` 结构实现方法 `new()`,允许初始化一个 `Person` 实例
impl Person {
// 使用提供的 `name` 和 `age` 创建一个新的 `Person`
fn new(name: String, age: u8) -> Self {
Person { name, age }
}
fn can_drink(&self) -> bool {
if self.age >= 21 as u8 {
return true;
}
return false;
}
fn age_in_one_year(&self) -> u8 {
return &self.age + 1;
}
}
fn main() {
// 用法:创建一个带有名字和年龄的新 `Person` 实例
let person = Person::new(String::from("Jesserc"), 19);
// 使用一些实现函数
println!("{:?}", person.can_drink()); // false
println!("{:?}", person.age_in_one_year()); // 20
println!("{:?}", person.name);
}
用法:
// 用法:创建一个带有名字和年龄的新 `Person` 实例
let person = Person::new(String::from("Jesserc"), 19);
// 使用一些实现函数
person.can_drink(); // false
person.age_in_one_year(); // 20
Rust traits 是在不同的 impl
之间实现共享行为的一种方式。可以将它们视为 Solidity 中的接口或抽象合约——任何使用该接口的合约必须实现某些函数。
例如,假设我们有一个需要定义汽车和船的结构的场景。我们想附加一个方法,允许我们以每小时公里数检索它们的速度。在 Rust 中,我们可以通过使用单个 trait 并在两个结构之间共享该方法来实现这个目标。
如下所示:
// traits 用 `trait` 关键字定义,后跟其名称
trait Speed {
fn get_speed_kph(&self) -> f64;
}
// 汽车结构
struct Car {
speed_mph: f64,
}
// 船结构
struct Boat {
speed_knots: f64,
}
// 使用 `impl` 关键字为类型实现 traits,如下所示
impl Speed for Car {
fn get_speed_kph(&self) -> f64 {
// 将英里每小时转换为公里每小时
self.speed_mph * 1.60934
}
}
// 我们也为 `Boat` 实现 `Speed` trait
impl Speed for Boat {
fn get_speed_kph(&self) -> f64 {
// 将节转换为公里每小时
self.speed_knots * 1.852
}
}
fn main() {
// 初始化一个 `Car` 和 `Boat` 类型
let car = Car { speed_mph: 60.0 };
let boat = Boat { speed_knots: 30.0 };
// 获取并打印以公里每小时为单位的速度
let car_speed_kph = car.get_speed_kph();
let boat_speed_kph = boat.get_speed_kph();
println!("Car Speed: {} km/h", car_speed_kph); // 96.5604 km/h
println!("Boat Speed: {} km/h", boat_speed_kph); // 55.56 km/h
}
在我们关于类似函数的宏的教程中,我们看到了宏如何扩展代码,比如 println!(...)
和 msg!(...)
在大型 Rust 代码中的用法。在 Solana 的上下文中,我们关心的另一种宏是 attribute-like 宏和 derive 宏。我们可以在 anchor 创建的启动程序中看到这三种宏(函数式、类似属性和派生):
为了直观了解类似属性的宏做了什么,我们将创建两个宏:一个将字段添加到结构中,另一个将其删除。
为了更好地理解 Rust 的属性和宏如何工作,我们将创建一个 attribute-like macro,其功能为:
foo
和 bar
字段的结构,字段类型为 i32
double_foo
的函数的 impl
,该函数返回 foo
字段所持的整数值的两倍。首先我们创建一个新的 Rust 项目:
cargo new macro-demo --lib
cd macro-demo
touch src/main.rs
在 Cargo.toml 文件中添加以下内容:
[li...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!