本文将阐释 Rust 中函数与类函数宏的区别,例如为何 msg! 后带有感叹号 !。我们将深入探讨这种语法的意义及其应用。
本文将阐释 Rust 中函数与类函数宏的区别,例如为何 msg! 后带有感叹号 !。我们将深入探讨这种语法的意义及其应用。
Rust 作为强类型语言,不支持函数接受任意数量的参数。例如,Python 的 print 函数可以灵活处理:
print(1) # 单个参数
print(1, 2) # 两个参数
print(1, 2, 3) # 三个参数
在 Rust 中,带有 ! 的语法(如 println! 或 msg!)表示这是一个类函数宏,而非普通函数。
Rust 中用于输出的普通函数是 std::io::stdout().write,它只接受单一字节切片参数:
use std::io::Write;
fn main() {
std::io::stdout().write(b"Hello, world!\n").unwrap(); // 输出字节切片
}
注意,write 是函数,没有 !。若尝试像 Python 那样传入多个参数,会编译失败:
use std::io::Write;
fn main() {
std::io::stdout().write(b"1\n").unwrap();
// std::io::stdout().write(b"1", b"2\n").unwrap(); // 编译失败:参数数量不匹配
}
若想支持任意参数数量,一个低效的办法是为每种参数个数编写特定函数:
use std::io::Write;
fn print1(arg1: &[u8]) { // 输出单个参数
std::io::stdout().write(arg1).unwrap();
}
fn print2(arg1: &[u8], arg2: &[u8]) { // 输出两个参数
let combined = [arg1, b" ", arg2].concat();
std::io::stdout().write(&combined).unwrap();
}
fn print3(arg1: &[u8], arg2: &[u8], arg3: &[u8]) { // 输出三个参数
let combined = [arg1, b" ", arg2, b" ", arg3].concat();
std::io::stdout().write(&combined).unwrap();
}
fn main() {
print1(b"1\n");
print2(b"1", b"2\n");
print3(b"1", b"2", b"3\n");
}
这种方法显然繁琐且不可扩展。Rust 的类函数宏通过动态生成代码解决了这一问题。
Rust 宏以 Rust 代码为输入,在编译时将其扩展为更复杂的代码。例如,println! 可以根据参数数量自动生成相应的输出逻辑,避免手动编写多个函数。
可用 cargo-expand 查看宏的扩展结果,但其输出冗长,此处不展示。
对于开发者而言,通常无需深入理解宏的内部实现。由库提供的宏(如 println!、msg!)使用方便,但手动编写宏较为复杂,涉及 Rust 代码的解析。
Rust 支持多种宏类型,以下是我们关注的几种:
以下是 Anchor 生成的程序示例:
use anchor_lang::prelude::*;
declare_id!("AcCKUb5GBSGgX1dz6GMTyvZwSBsnnzZJigac9kB7cfXr"); // 类函数宏:声明程序 ID
#[program] // 属性宏:定义 Solana 程序
pub mod macro_example {
use super::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
Ok(())
}
}
#[derive(Accounts)] // 自定义派生宏:为结构体生成账户验证逻辑
pub struct Initialize {}
这些宏的具体工作原理将在后续文章中详细讲解。
【笔记配套代码】 https://github.com/0xE1337/rareskills_evm_to_solana 【参考资料】 https://learnblockchain.cn/column/119 https://www.rareskills.io/solana-tutorial
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!