本教程深入探讨了Solidity和Rust在控制流、数组、映射、结构体和常量等方面的语法对比,旨在帮助掌握Solidity的开发者快速上手Rust编程。
本教程介绍了在 Solidity 中最常用的语法,并展示了其在 Rust 中的等价实现。
如果你想了解 Rust 与 Solidity 之间的高层次差异,请查看链接的教程。本教程假设你已经了解 Solidity,假如你对 Solidity 不熟悉,请查看我们免费的 Solidity 教程。
创建一个名为 tryrust
的新 Solana Anchor 项目并设置环境。
我们可以说,开发人员在 Solidity 中可以根据特定条件控制执行流程的方式有 2 种:
现在让我们看看上述内容在 Solidity 中的实现,以及它们在 Solana 中的翻译。
在 Solidity 中:
function ageChecker(uint256 age) public pure returns (string memory) {
if (age >= 18) {
return "你已满 18 岁或以上";
} else {
return "你未满 18 岁";
}
}
在 Solana 中,在 lib.rs 中添加一个名为 age_checker
的新函数:
pub fn age_checker(ctx: Context<Initialize>, age: u64) -> Result<()> {
if age >= 18 {
msg!("你已满 18 岁或以上");
} else {
msg!("你未满 18 岁");
}
Ok(())
}
请注意,条件 age >= 18
没有括号——这在 if 语句中是可选的。
要测试,请在 ./tests/tryrust.ts
中添加另一个 it
块:
it("年龄检查", async () => {
// 在这里添加你的测试。
const tx = await program.methods.ageChecker(new anchor.BN(35)).rpc();
console.log("你的交易签名", tx);
});
运行测试后,我们应该得到以下日志:
Transaction executed in slot 77791:
Signature: 2Av18ej2YjkRhzybbccPpwEtkw73VcBpDPZgC9iKrmf6mvwbqjA517garhrntWxKAM1ULL2eAv5vDWJ3SjnFZq6j
Status: Ok
Log Messages:
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX invoke [1]
Program log: Instruction: AgeChecker
Program log: 你已满 18 岁或以上
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX consumed 440 of 200000 compute units
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX success
在 Solidity 中将 if-else 语句分配给变量:
function ageChecker(uint256 age) public pure returns (bool a) {
a = age % 2 == 0 ? true : false;
}
在 Solana 中,我们基本上只是将一个 if-else 语句分配给一个变量。下面的 Solana 程序与上述相同:
pub fn age_checker(ctx: Context<Initialize>, age: u64) -> Result<()> {
let result = if age >= 18 {"你已满 18 岁或以上"} else { "你未满 18 岁" };
msg!("{:?}", result);
Ok(())
}
请注意,在 Rust 的三元运算符示例中,if/else 块以分号结尾,因为这是分配给一个变量的。
还要注意,内部值没有以分号结尾,因为它作为返回值返回给变量,就像在表达式而不是语句的情况下不在 Ok(())
之后加分号一样。
如果年龄是偶数,程序将输出 true,否则为 false:
Transaction executed in slot 102358:
Signature: 2zohZKhY56rLb7myFs8kabdwULJALENyvyFS5LC6yLM264BnkwsThMnotHNAssJbQEzQpmK4yd3ozs3zhG3GH1Gx
Status: Ok
Log Messages:
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX invoke [1]
Program log: Instruction: AgeChecker
Program log: true
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX consumed 792 of 200000 compute units
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX success
Rust 还有一个更强大的控制流结构叫做 match。让我们看看下面的使用 match 的示例:
pub fn age_checker(ctx: Context<Initialize>, age: u64) -> Result<()> {
match age {
1 => {
// 如果年龄等于 1 则执行的代码块
msg!("年龄是 1");
},
2 | 3 => {
// 如果年龄等于 2 或 3 则执行的代码块
msg!("年龄是 2 或 3");
},
4..=6 => {
// 如果年龄在 4 到 6(包括)之间则执行的代码块
msg!("年龄在 4 到 6 之间");
},
_ => {
// 任何其他年龄的代码块
msg!("年龄是其他值");
}
}
Ok(())
}
我们知道,for 循环允许遍历范围、集合和其他可迭代对象,在 Solidity 中是这样写的:
function loopOverSmth() public {
for (uint256 i=0; i < 10; i++) {
// 做一些事情...
}
}
这在 Solana(Rust)中的等价实现为:
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
for i in 0..10 {
// 做一些事情...
}
Ok(())
}
是的,简单如斯,但我们如何使用自定义步长遍历范围呢?以下是在 Solidity 中的预期行为:
function loopOverSmth() public {
for (uint256 i=0; i < 10; i+=2) {
// 做一些事情...
// 将 i 增加 2
}
}
在 Solana 中使用 step_by
的等价实现是:
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
for i in (0..10).step_by(2) {
// 做一些事情...
msg!("{}", i);
}
Ok(())
}
运行测试后,我们应该获得以下日志:
Transaction executed in slot 126442:
Signature: 3BSPA11TZVSbF8krjMnge1fgwNsL9odknD2twAsDeYEF39AzaJy1c5TmFCt6LEzLtvWnjzx7VyFKJ4VT1KQBpiwm
Status: Ok
Log Messages:
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX invoke [1]
Program log: Instruction: Initialize
Program log: 0
Program log: 2
Program log: 4
Program log: 6
Program log: 8
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX consumed 2830 of 200000 compute units
Program 53hgft52DHUKMPHGu1kusuwxFGk2T8qngwSw2SyGRNrX success
Rust 和 Solidity 在数组支持上有所不同。虽然 Solidity 原生支持固定和动态数组,但 Rust 仅内置支持固定数组。如果你想要动态长度的列表,请使用向量。
现在,让我们看一些示例,演示...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!