Solidity 入门
基本语法
版本指令
所有Solidity源码都必须指明版本,用于标明Solidity编译器的版本,这是为了避免将来新的编译器破坏代码
pragma solidity ^0.4.20; // 声明版本 // 定义一个合约 contract AntFamily { }
状态变量
状态变量是定义在合约内部,但是不在函数内部的变量,会永久保存在合约存储空间中,也就说它们会被写入区块链中
pragma solidity ^0.4.20; contract AntFamily { uint dnaDigits = 12; }
数学运算
在 Solidity 中,数学运算与其它程序设计语言相同:
- 加法: x + y
- 减法: x - y
- 乘法: x * y
- 除法: x / y
- 取模: x % y
- 幂运算:x ** y
// 表示6的2次方 uint a = 6 ** 2;
结构体
通过结构体来定义新的类型,结构体允许生成一个更复杂的数据类型,可以有多个属性
struct Book { string name; uint page; }
函数定义
习惯上函数里的变量都是以(_)开头 (不是硬性规定) 以区别全局变量
function buyBook(string _name, uint _count) { }
数组
如果想建立一个集合,可以使用数组这种数据类型,支持两种数组: 静态数组和动态数组
// 固定长度为3的静态数组: uint[3] fixedArray; // 固定长度为5的string类型的静态数组: string[6] stringArray; // 动态数组,长度不固定,可以动态添加元素: uint[] dynamicArray;
也可以建立一个结构体类型的数组:
Book[] books;
状态变量被永久保存在区块链中,所以在合约中创建动态数组来保存结构化的数据是非常有意义的
公共数组:
Book[] public books;
数组和结构体的使用
如下传见了Ant结构体,和Ant类型的数组,定义了ceateAnt函数:
pragma solidity ^0.4.20; contract AntFamily { uint dnaDigits = 12; uint dnaModulus = 10 ** dnaDigits; struct Ant { string name; uint dna; } Ant[] public ants; function createAnt(string _name, uint _dna) { ants.push(Ant(_name,_dna)); // 创建一个结构体并添加到数组中 } }
keccak256散列函数的使用
该函数将一个字符串转换为一个256位的16进制数字
//bc6bb462e38af7da48e0ae7b5cbae860141c04e5af2cf92328cd6548df111fcb keccak256('xxx'); //3a60bbc72c8477330650d5aae5e7d73f0d15a6efe7e8aab4fa3c33a3a8c3b467 keccak256('xxy');
事件
事件
是合约和区块链通讯的一种机制,应用可以“监听”某些事件,并做出反应,使用event
关键字来定义事件,使用emit
关键字在函数中触发事件
pragma solidity ^0.4.20; contract AntFamily { event NewAnt(uint indexed antId,string name,uint dna); uint dnaDigits = 12; uint dnaModulus = 10 ** dnaDigits; struct Ant { string name; uint dna; } Ant[] public ants; function createAnt(string _name, uint _dna) { uint id = ants.push(Ant(_name, _dna))-1; emit NewAnt(id,_name,_dna); } function createRandomAnt(string _name) { uint rand = uint(keccak256(_name)); uint randDna = rand % dnaModulus; createAnt(_name, randDna); } }
复杂组合
pragma solidity ^0.4.20; contract AntFamily { event NewAnt(uint indexed antId, string name, uint dna); event NewHouse(uint indexed houseId,string name,uint existGoods,uint maxGoods); uint dnaDigits = 12; uint dnaModulus = 10 ** dnaDigits; struct Ant { string name; uint dna; } struct House { string name; uint existGoods; uint maxGoods; } Ant[] public ants; House[] public houses; function createAnt(string _name, uint _dna) { uint id = ants.push(Ant(_name, _dna)) - 1; emit NewAnt(id, _name, _dna); } function createRandomAnt(string _name) { uint rand = uint(keccak256(_name)); uint randDna = rand % dnaModulus; createAnt(_name, randDna); } function createHouse(string _houseName,uint _existGoods,uint _maxGoods) { uint houseId = houses.push(House(_houseName,_existGoods,_maxGoods))-1; emit NewHouse(houseId,_houseName,_existGoods,_maxGoods); } }
映射
//可以用来通过userId 存储/查找的用户名 mapping (uint => string) userIdToName;
使用:
pragma solidity ^0.4.20; contract AntFamily { event NewAnt(uint indexed antId, string name, uint dna); event NewHouse(uint indexed houseId, string name, uint existGoods, uint maxGoods); uint dnaDigits = 12; uint dnaModulus = 10 ** dnaDigits; struct Ant { string name; uint dna; } struct House { string name; uint existGoods; uint maxGoods; } Ant[] public ants; House[] public houses; mapping (uint => identity) public antToOwner; mapping (identity => uint) ownerAntCount; mapping (uint => identity) houseToOwner; function createAnt(string _name, uint _dna) { uint id = ants.push(Ant(_name, _dna)) - 1; antToOwner[id] = msg.sender; ownerAntCount[msg.sender]++; emit NewAnt(id, _name, _dna); } function createRandomAnt(string _name) { uint rand = uint(keccak256(_name)); uint randDna = rand % dnaModulus; createAnt(_name, randDna); } function createHouse(string _houseName, uint _existGoods, uint _maxGoods) { uint houseId = houses.push(House(_houseName, _existGoods, _maxGoods)) - 1; houseToOwner[houseId] = msg.sender; emit NewHouse(houseId, _houseName, _existGoods, _maxGoods); } }
require
使得函数在执行过程中,当不满足某些条件时抛出错误,并停止执行
function sayHiToBob(string _name) public returns (string) { // 比较 _name 是否等于 "Bob". 如果不成立,抛出异常并终止程序 require(keccak256(_name) == keccak256("Bob")); // 如果返回 true, 运行如下语句 return "Hi!"; }
这样调用函数 sayHiToBob(“Bob”),它会返回“Hi!”。而如果你调用的时候使用了其他参数,它则会抛出错误并停止执行。 因此,在调用一个函数之前,用 require 验证前置条件是非常有必要的
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构