大家好,如果大家对 Solana 开发充满好奇,但又对 Rust 语言感到陌生,那么大家来对地方了。很多人在探索 Solana 这条高性能公链时,遇到的第一个门槛就是其原生开发语言——Rust。Rust 以其高性能和内存安全著称,但学习曲线也相对陡峭。

幸运的是,我们有 Anchor —— 一个能让我们“站在巨人肩膀上”的开发框架。它通过一系列宏(Macro)和约定,将复杂的 Solana 底层交互封装起来,让我们能更专注于业务逻辑本身。

今天,我们就以 Solana 官方文档的第一个入门项目为例,一步步剖析代码,让大家不仅知道“怎么做”,更明白“为什么这么做”,顺便带大家入门 Rust 的核心语法。在这里插入图片描述

准备工作:创建我们的 Anchor 项目

在开始之前,我们需要根据官方文档指引,安装好 Rust、Solana CLI 和 Anchor CLI。

安装完成后,打开我们的终端,输入以下命令来创建一个新的项目:

anchor init my-first-solana-app
cd my-first-solana-app

这个命令会为我们生成一个标准化的项目结构,其中最重要的文件就是 programs/my-first-solana-app/src/lib.rs。这里存放着我们链上程序(Program)的核心逻辑。现在,让我们打开它,一探究竟!

代码深潜:逐行解析 lib.rs

初次看到 lib.rs 里的代码,我们可能会有点懵。别担心,我们把它拆成几个部分来看,我们会发现它像乐高积木一样,每一块都有清晰的功能。

这是文件的完整内容:

use anchor_lang::prelude::*;declare_id!("E3xcTbTbCYtc6XMyXv2QHBgKAeFDLqEWHCqxExpJqLsC");#[program]
pub mod my_first_solana_app {use super::*;pub fn initialize(ctx: Context<Initialize>) -> Result<()> {msg!("Greetings from: {:?}", ctx.program_id);Ok(())}
}#[derive(Accounts)]
pub struct Initialize {}
1. use anchor_lang::prelude::*; - 导入“工具箱”
  • Rust 语法点 (useprelude):
    • use 关键字在 Rust 中用于将外部模块(库)的功能引入到当前作用域。就好比在 Python 中写 import
    • prelude(序曲)是一种常见的 Rust 编程模式。库的作者会把最常用、最核心的组件放进一个叫 prelude 的模块里。通过 use ...::prelude::*;,我们可以一次性导入所有必需品,省去了逐个导入的麻烦。
  • 具体作用: 这里我们导入了 anchor_lang 库的预置模块,它包含了构建 Anchor 程序所需的大部分基础类型和宏,比如 Context, Result, msg! 等。
2. declare_id!("...") - 声明程序的“身份证号”
  • Rust 语法点 (宏 !):
    • 在 Rust 中,任何以 ! 结尾的调用,都不是函数调用,而是**宏(Macro)**调用。宏可以理解为“代码的代码”,它能在编译时生成或转换代码,功能非常强大。
  • 具体作用: declare_id! 是 Anchor 提供的一个宏。每个部署到 Solana 链上的程序都有一个唯一的地址,就像我们的身份证号一样。这个宏的作用就是将我们的程序逻辑与这个链上地址绑定起来。当我们运行 anchor deploy 时,Anchor 会自动生成一个新的地址,并帮我们更新到这里。
3. #[program] - 神奇的“魔法帽”
  • Rust 语法点 (属性宏 #[...]):
    • 形如 #[thing] 的语法是 Rust 的属性宏。它可以附加到函数、模块、结构体等代码块上,像一个“魔法帽”,为其附加额外的行为或进行代码转换。
  • 具体作用: #[program] 是 Anchor 框架的核心。它会“扫描”紧跟其后的 mod(模块),找到所有公开的函数(比如 initialize),并将它们自动转换为符合 Solana 规范的**指令(Instruction)**处理器。它帮我们处理了大量繁琐的底层工作,比如指令数据的反序列化、账户信息的解析等。
4. pub mod my_first_solana_app { ... } - 程序的主体模块
  • Rust 语法点 (modpub):
    • mod 关键字用于定义一个模块(Module),它是 Rust 组织代码的基本单元,类似于一个命名空间。
    • pub 关键字表示“公开的”(public),意味着这个模块或函数可以被外部访问。
  • 具体作用: 这里定义了一个名为 my_first_solana_app 的公共模块,我们的指令逻辑都将写在这里面。
5. pub fn initialize(ctx: Context<Initialize>) -> Result<()> - 第一个指令

这是我们程序的第一个,也是唯一一个指令。让我们把它拆得更细:

  • pub fn initialize: 定义一个名为 initialize 的公共函数。因为 #[program] 的存在,这个函数会成为一个可以从客户端(例如一个网页或脚本)调用的指令。

  • ctx: Context<Initialize>: 这是理解 Anchor 的关键!

    • ctx 是参数名,Context<Initialize> 是它的类型。
    • Context 是 Anchor 提供的一个容器,它安全地包含了与本次调用相关的所有**账户(Accounts)**信息。在 Solana 中,所有数据(包括用户信息、程序状态等)都存储在账户里。程序本身是无状态的,它只是逻辑。
    • <Initialize> 是一个泛型参数,它告诉 Context:“嘿,请按照 Initialize 这个结构体里定义的规则来准备和校验我需要的账户。”
  • -> Result<()>: 这是函数的返回值类型。

    • Rust 语法点 (Result()):
      • Result 是 Rust 用于错误处理的标准枚举类型。一个 Result 要么是 Ok(value) 表示成功并携带一个值,要么是 Err(error) 表示失败并携带一个错误信息。这强迫开发者必须处理可能发生的错误,是 Rust 安全性的重要体现。
      • () 是一个特殊的类型,叫做单元类型(Unit Type)。它表示“没有具体的值”,类似于其他语言中的 voidnull
      • 所以 Result<()> 的意思是:如果函数成功,它不返回任何有意义的数据,只返回一个成功的信号;如果失败,它会返回一个错误。
  • msg!("Hello from your first Solana program!");: 调用 msg! 宏,在链上日志中打印一条信息。这是我们在链上调试时最常用的工具,相当于 console.logprint

  • Ok(()): 表示函数成功执行。我们创建一个 Ok 变体,并用 () 作为其内容,以匹配 Result<()> 的返回类型。

6. #[derive(Accounts)]pub struct Initialize {} - 定义账户规则
  • Rust 语法点 (struct#[derive]):
    • struct(结构体)是 Rust 中创建自定义数据类型的方式,它是一个字段的集合。
    • #[derive(...)] 是另一个非常有用的属性宏。它能为一个结构体自动实现某些标准的行为(在 Rust 中称为 Traits)。
  • 具体作用:
    • pub struct Initialize {} 定义了一个名为 Initialize 的结构体。
    • #[derive(Accounts)] 是 Anchor 提供的宏,它会读取 Initialize 结构体,并自动生成账户解析和安全校验的代码。
    • 在我们这个例子中,Initialize 是一个空结构体 {},因为它所对应的 initialize 指令不需要任何外部账户作为输入。在一个更复杂的程序中,我们可能会在这里定义需要传入的用户账户、数据账户等。例如:
      // 这是一个虚构的例子
      #[derive(Accounts)]
      pub struct UpdateScore<'info> {#[account(mut)]pub player_stats: Account<'info, PlayerStats>, // 需要一个可修改的玩家状态账户pub signer: Signer<'info>, // 需要交易发起者的签名
      }
      
流程串讲:它们是如何协同工作的?

现在,我们用一个流程图来把所有部分串联起来,看看当一个用户调用我们的 initialize 指令时,背后发生了什么。
在这里插入图片描述

这个流程清晰地展示了 Anchor 如何作为我们和底层 Solana 之间的“智能中间层”,帮我们处理了最棘手的账户校验环节,让我们可以安心地编写核心业务逻辑。

实用建议
  1. 大胆使用 msg!:在我们学习的早期阶段,不要吝啬使用 msg!。在函数的开头、中间、结尾打印信息,可以帮我们直观地理解代码的执行流程。
  2. 运行测试:在项目根目录运行 anchor test。这个命令会编译我们的程序,将其部署到一个本地的测试节点,并运行 tests/ 目录下的脚本来调用我们的指令。阅读测试脚本,可以帮我们理解如何从客户端与程序交互。
  3. 做个小修改:尝试修改 msg! 中的字符串,然后重新运行 anchor test,看看日志输出是否变化。这个简单的练习可以建立我们对“编码->部署->测试”循环的信心。
总结

我们已经完成了对第一个 Solana 程序的深度剖析。我们来回顾一下核心要点:

  • Anchor 是我们的好朋友:它通过 #[program]#[derive(Accounts)] 等宏,极大地简化了开发。
  • Rust 没那么可怕:我们接触了它的模块(mod)、函数(fn)、结构体(struct)、错误处理(Result)以及强大的宏系统。这些特性共同构建了一个安全而高效的编程环境。
  • 一切皆账户:Solana 的核心是账户模型,Anchor 的 Context#[derive(Accounts)] 为我们提供了安全、便捷的方式来操作账户。

从这个简单的 “Hello World” 出发,我们已经掌握了理解更复杂 Solana 程序的基础。继续探索,尝试为我们的程序添加状态,或者定义需要更多账户的指令。编程之路,始于足下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91657.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91657.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/91657.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

node.js之Koa框架

Koa框架介绍Koa 是一个新的 web 框架&#xff0c;由 Express 原班人马打造&#xff0c;致力于成为一个更小、更富有表现力、更健壮的 Web 框架。Koa 解决了 Express 存在的一些问题&#xff0c;例如&#xff1a;中间件嵌套回调&#xff08;callback hell&#xff09;错误处理不…

C/C++离线环境安装(VSCode + MinGW)

因为工作需要部署离线C环境&#xff0c;网上有许多大佬分享了不错的教程&#xff0c;总结一篇完整教程自用&#xff0c;使用VSCode MinGW感谢一、安装准备二、软件安装1.安装MinGW2.安装VSCode及插件三、测试环境1.创建工程文件夹2.创建cpp文件总结感谢 本教程参考了以下教程…

如何创建一个飞书应用获取自己的飞书AppID和AppSecret?

这篇文章是接下来要开发「监控 X&#xff08;原Twitter&#xff09;博主账号最新推文」 自动化工作流的先导文章&#xff0c;由于内容相对独立&#xff0c;也可用于飞书应用的其他场景&#xff0c;故单独发出来&#xff0c;方便查阅。 监控X平台指定博主最新发文&#xff0c;需…

Prompt工程记录

Prompt基本建议&#xff1a;1.在查询中包含详细信息以获得更相关的答案总结会议笔记:先将会议笔记总结为一段&#xff0c;然后写一份演讲者的打分表&#xff0c;列出他们的每个要点&#xff1b;最后列出发言者建议的下一步行动或者行动项目&#xff08;如果有的话&#xff09;2…

CTE公用表表达式的可读性与性能优化

一、可读性优化CTE通过WITH子句定义临时命名结果集&#xff0c;将复杂查询分解为逻辑独立的模块&#xff0c;显著提升代码清晰度与可维护性‌&#xff1a;‌解构嵌套查询‌&#xff1a;将多层嵌套的子查询扁平化&#xff0c;例如传统嵌套统计订单的查询可重构为分步CTE&#xf…

8.1.2 TiDB存储引擎的原理

TiDB 简介 TiDB 是 PingCAP 公司自主设计、研发的开源分布式关系型数据 库&#xff0c;是一款同时支持在线事务处理与在线分析处理 (Hybrid Transactional and Analytical Processing, HTAP) 的融合型分布 式数据库产品&#xff0c;具备水平扩容或者缩容、金融级高可用、实时 …

PTE之路--01

空格绕过:/**/ URL编码伪协议:pagezip://xxx/xx/x/x/xxx.jpg%23解压后的名字pagephar://xxx/xx/x/x/xxx.jpg/解压后的名字pageddata://ata://text/plain,<?php eval($_POST[x]) ;?>pagedata://text/plain,<?php eval($_POST[x]) ;?>127.0.0.1 | grep . ../key…

企业级日志分析系统ELK

1.什么是 Elastic Stack 如果系统和应用出现异常和问题,相关的开发和运维人员想要排查原因,就要先登录到应用运行所相应的主机,找到上面的相关日志文件再进行查找和分析,所以非常不方便,此外还会涉及到权限和安全问题,而ELK 的出现就很好的解决这一问题。 ELK 是由一家 …

ai项目多智能体

手把手教你构建一个 本地化的&#xff0c;免费的&#xff0c;企业级的&#xff0c;AI大模型知识库问答系统 - 网旭哈瑞.AI 体验 AutoGen Studio - 微软推出的友好多智能体协作框架_autogenstudio-CSDN博客 AutoGen Studio: Interactively Explore Multi-Agent Workflows | Au…

【HTML】浅谈 script 标签的 defer 和 async

The async and defer attributes are boolean attributes that indicate how the script should be evaluated. There are several possible modes that can be selected using these attributes, depending on the script’s type. async 和 defer 属性是布尔属性&#xff0c;…

Kafka Streams 并行处理机制深度解析:任务(Task)与流线程(Stream Threads)的协同设计

在构建实时流处理应用时&#xff0c;如何充分利用计算资源同时保证处理效率是一个关键问题。Kafka Streams 通过其独特的任务(Task)和流线程(Stream Threads)并行模型&#xff0c;为开发者提供了既简单又强大的并行处理能力。本文将深入解析 Kafka Streams 中任务与线程的协同工…

使用 Docker 部署 Label Studio 时本地文件无法显示的排查与解决

目录 使用 Docker 部署 Label Studio 时本地文件无法显示的排查与解决 1. 背景 2. 问题现象 3. 排查步骤 3.1 确认文件是否存在 3.2 检查环境变量配置 4. 解决方案 方法一&#xff1a;修改 Sync Storage 路径&#xff08;相对路径&#xff09; 方法二&#xff1a;修改…

ElasticJob怎么使用?

我们使用ElasticJob需要以下步骤&#xff1a; 1. 添加依赖 2. 配置任务&#xff08;可以使用Spring命名空间配置或Java配置&#xff09; 3. 实现任务逻辑&#xff08;实现SimpleJob、DataflowJob等接口&#xff09; 4. 启动任务 下面是一个详细的示例&#xff0c;包括Spring Bo…

TCP协议的特点和首部格式

文章目录TCP协议是什么&#xff1f;TCP协议的主要特点1. 面向连接2. 可靠传输3. 流量控制4. 拥塞控制TCP首部格式源端口和目标端口&#xff08;各16位&#xff09;序列号&#xff08;32位&#xff09;确认号&#xff08;32位&#xff09;数据偏移&#xff08;4位&#xff09;保…

IO流-文件的常用方法

1.关于java.io.File类- File类只能表示计算机中的文件或目录而不能获取或操作文件- 通过File类获得到文件的基本信息&#xff0c;如文件名、大小等&#xff0c;但不能获取文件内容- java中表示文件路径分隔符使用"/"或"\\"- File类中的构造方法- File(&quo…

AUTOSAR进阶图解==>AUTOSAR_SRS_E2E

AUTOSAR E2E通信保护解析 AUTOSAR End-to-End通信保护机制详解与应用目录 概述 1.1. AUTOSAR E2E通信保护的作用 1.2. E2E通信保护的应用场景AUTOSAR E2E架构 2.1. E2E组件层次结构 2.2. E2E库和E2E转换器E2E监控状态机 3.1. 状态定义与转换 3.2. 状态机实现E2E保护数据交换流…

镜像快速部署ollama+python+ai

算力租赁入口&#xff1a;https://www.jygpu.com为大家提供以上镜像快速部署方式&#xff0c;节约大家环境部署时间一键部署的便捷性传统自建GPU服务器需要经历复杂的硬件采购、驱动安装、环境配置等繁琐步骤&#xff0c;而现代​​GPU租赁价格对比​​显示&#xff0c;容器化平…

使用Gemini API开发领域智能聊天机器人的思路

以下是使用 Gemini API 开发软件自动化测试专家领域专属智能聊天机器人的详细思路及具体实现过程&#xff1a; 阶段一&#xff1a;基础准备与规划 (Foundation & Planning) 这个阶段的目标是明确方向、准备好所有必要的工具和凭证。 步骤 1&#xff1a;明确聊天机器人的目…

第13届蓝桥杯Python青少组_省赛_中/高级组_2022年4月17日真题

更多内容请查看网站&#xff1a;【试卷中心 -----> 蓝桥杯----> Python----> 省赛】 网站链接 青少年软件编程历年真题模拟题实时更新 第13届蓝桥杯Python青少组_省赛_中/高级组_2022年4月17日真题 一、选择题 第 1 题 下列二进制数中最大的是&#xff08; &a…

sqli-labs:Less-17关卡详细解析

1. 思路&#x1f680; 本关的SQL语句为&#xff1a; $sql"SELECT username, password FROM users WHERE username $uname LIMIT 0,1"; $update"UPDATE users SET password $passwd WHERE username$row1";注入类型&#xff1a;字符串型&#xff08;单引号…