本教程详细解释了Rust中函数与函数式宏的区别,并通过代码示例展示了如何使用Rust的函数式宏来处理不同数量的参数。
本教程解释了函数与函数式宏之间的区别。例如,为什么
msg!
后面有一个感叹号?本教程将解释这种语法。作为一种强类型语言,Rust 不能接受函数的任意数量的参数。例如,Python 的 print
函数可以接受任意数量的参数:
print(1)
print(1, 2)
print(1, 2, 3)
!
表示“函数”是一个函数式宏。Rust 的函数式宏通过 !
符号来标识,例如 Solana 中的 println!(...)
或 msg!(...)
。在 Rust 中,打印内容的常规函数(非函数式宏)是 std::io::stdout().write
,它只接受一个字节字符串作为参数。如果你想运行以下代码,如果你不想设置开发环境,Rust Playground 是一个方便的工具。我们使用以下示例(取自这里):
use std::io::Write;
fn main() {
std::io::stdout().write(b"Hello, world!
").unwrap();
}
请注意,write
是一个函数,而不是宏,因为它没有 !
。如果你尝试像上面在 Python 中那样做,代码将无法编译,因为 write
只接受一个参数:
// 这段代码无法编译
use std::io::Write;
fn main() {
std::io::stdout().write(b"1
").unwrap();
std::io::stdout().write(b"1", b"2
").unwrap();
std::io::stdout().write(b"1", b"2", b"3
").unwrap();
}
因此,如果你想打印任意数量的参数,你需要为每种参数数量编写一个自定义的 print
函数来处理每种情况 —— 这是非常低效的!以下是这样代码的样子(非常不推荐!):
use std::io::Write;
// 打印一个参数
fn print1(arg1: &[u8]) -> () {
std::io::stdout().write(arg1).unwrap();
}
// 打印两个参数
fn print2(arg1: &[u8], arg2: &[u8]) -> () {
let combined_vec = [arg1, b" ", arg2].concat();
let combined_slice = combined_vec.as_slice();
std::io::stdout().write(combined_slice).unwrap();
}
// 打印三个参数
fn print3(arg1: &[u8], arg2: &[u8], arg3: &[u8]) -> () {
let combined_vec = [arg1, b" ", arg2, b" ", arg3].concat();
let combined_slice = combined_vec.as_slice();
std::io::stdout().write(combined_slice).unwrap();
}
fn main() {
print1(b"1
");
print2(b"1", b"2
");
print3(b"1", b"2", b"3
");
}
如果我们观察 print1
、print2
、print3
函数中的模式,它只是将参数插入到向量中并在它们之间添加一个空格,然后将向量转换回字节字符串(准确说是字节切片)。如果我们能像 println!
这样编写一段代码,并自动将其扩展为一个 print
函数,接受我们所需的任意数量的参数,那岂不是很好?这就是 Rust 宏的作用。Rust 宏将 Rust 代码作为输入,并以编程方式将其扩展为更多的 Rust 代码。 这帮助我们避免了必须为代码所需的每种 print
语句编写 print
函数的无聊工作。
要查看 Rust 编译器如何扩展 println!
宏的示例,请查看 cargo expand github 仓库。结果相当冗长,所以我们不在这里展示。
当宏由库提供时,它们非常方便,但手动编写宏非常繁琐,因为它需要字面解析 Rust 代码。
我们给出的 println!
示例是一个函数式宏。Rust 还有其他类型的宏,但我们关心的另外两种是自定义派生宏和属性式宏。让我们看看 anchor 创建的新程序:我们将在接下来的教程中解释它们的工作原理。
本教程是我们免费 Solana 教程 的一部分。 最初发布于 2024 年 2 月 15 日
- 原文链接: rareskills.io/post/rust-...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!