第一行
Solidity 第一行用注释来写SPDX License Identifier
虽然是可选的,但是有些编译器会出现警告
(资料图)
用来定义license和代码分享规则
//SPDX-License-Identifier:MIT
MIT是限制最少的license之一,大多数代码都是用MIT
第二行
solidity是一个更新迭代比较快的语言,因此sol文件第二行用来声明版本
如下明确声明了只使用0.8.7版本
pragma solidity 0.8.7; // 使用双斜线进行注释,第一行是声明使用solidity的版本
同时也可以在0.8.7前面添加一个^ 用来声明此代码运行环境能在0.8.7及之后运行
pragma solidity ^0.8.7;
如果用一个区间表示,用如下方式表示本代码运行环境位于以下区间
pragma solidity >=0.8.7 <0.9.0; //表示0.8.7 0.8.8 0.8.9适用但0.9.0不适用
智能合约的开始
使用 contract
用来高速编译器后面的代码是定义智能合约的。contract
是智能合约的关键之之一。
类似于java 的 class
//SPDX-License-Identifier:MITpragma solidity 0.8.7; // 使用双斜线进行注释,第一行是声明使用solidity的版本contract SimpleStorage {}
值类型
类型
描述
运算符
bool
布尔类型 true、false
!
(逻辑非)
&&
(逻辑与, “and” )
||
(逻辑或, “or” )
==
(等于)
!=
(不等于)
int/uint
分别表示有符号和无符号的不同位数的整型变量。 支持关键字 uint8
到 uint256
(无符号,从 8 位到 256 位)以及 int8
到 int256
,以 8
位为步长递增。 uint
和 int
分别是 uint256
和 int256
的别名。最大uint256,默认也是uint256。通常开发时把分配空间写出来。 uint8表示分配了8个bit,二进制表示为11111111
8个1,所以最大能表示255。256就不能用uint8声明了。
比较运算符: <=
, <
, ==
, !=
, >=
, >
(返回布尔值)
位运算符: &
, |
, ^
(异或), ~
(位取反)
移位运算符: <<
(左移位) , >>
(右移位)
算数运算符: +
, -
, 一元运算负 -
(仅针对有符号整型), *
, /
, %
(取余或叫模运算) , **
(幂)
address
保存一个20字节的值(以太坊地址的大小)
address payable
可支付地址,与 address
相同,不过有成员函数 transfer
和 send
举例:
bool hasFavoriteNumber = true;uint8 favoriteNumber = 123;uint number = 123;
函数
//SPDX-License-Identifier:MITpragma solidity 0.8.7; // 使用双斜线进行注释,第一行是声明使用solidity的版本contract SimpleStorage { int8 public number = 123; //函数 function changeNumber (int8 _number) public { number = _number; }}
函数用 function
声明,类似于js。但要在后面跟一个访问修饰符
一共有四个访问修饰符
public
:内部、外部均可见(参考为存储/状态变量创建 getter 函数)
private
:仅在当前合约内可见
external
:仅在外部可见(仅可修饰函数)——就是说,仅可用于消息调用(即使在合约内调用,也只能通过 this.func
的方式)
internal
:仅在内部可见。只有这个合约或集成他的合约能读取(也就是在当前 Solidity 源代码文件内均可见,不仅限于当前合约内,译者注)
变量的默认访问修饰符时 internal
gas消耗
执行上面代码后,可以在控制台看到所消耗的gas是2472 gas
当在函数中添加一行 number = number +1
时,执行相同操作,可以看到消耗的gas增加了更多
solidity有两个关键字,标识函数调用不需要消耗gas。分别是 view
和 pure
。
在区块链中,只有更改状态的时候才支付gas,发起交易。
如下图,number 和 review 是蓝色,而 changeNumber是黄色,下图中有gas
下面的number调用记录就没有gas一行
上图中的 execution cost 2472 gas (Cost only applies when called by a contract)
表示调用这个函数所需要花费的gas
function review() public view returns (int8){ return number; }
view
表示只会读取这个合约的状态。如上面的review函数,只能读取number并返回。不允许修改任何状态。pure
也不允许修改任何状态。但 pure
还不允许读取区块链上的数据。所以用 pure
修饰不能读取number。
pure
修饰的方法类似于下面,可能是常用的方法,或者是某个不需要读取数据的算法。
function add() public pure returns (int256){ return (1 + 1);}
int8 public number = 123; //带有public的变量可以看作是一个返回int8的view函数
结构体
一个简单的结构体示例
//定义struct People{ int8 number; string name;}//使用People public person1 = People({number:2,name:"furao"});
部署合约后,点击 person1
可以看到
(在solidity中的结构体可以先使用后声明,同js一样)
数组
//声明一个动态数组(因为没有规定他的大小)People[] public peoples;//如果在中括号里加一个数字,则声明这个数组中大小是3,不可变People[3] public peoples;
向数组中添加数据
//定义 struct People{ int8 number; string name; } //声明一个动态数组(因为没有规定他的大小) People[] public peoples; //向数组中添加一个数据 function addPerson (string memory _name,int8 _number) public { //写法1 People memory newPerson = People({name:_name,number:_number}); peoples.push(newPerson); //写法2 省略中间变量new Person peoples.push(People({name:_name,number:_number})); //写法3 根据people属性的顺序直接添加。同java,但没有new字 peoples.push(People(_number,_name)); }
将代码放入编译器,运行
memory、storage、calldata
上述 addPerson
方法中,声明入参的时候有一个 memory
进行描述。如果删了它,则会编译报错。
TypeError: Data location must be "memory" or "calldata" for parameter in function, but none was given.
目前在solodity中,有6种方式进行存储数据
stake
memory
storage
calldata
code
logs
临时变量有 memory
和 calldata
,calldata
不能被修改(赋值)。memory
可以被修改。storage
是用永久变量。
function addPerson (string memory _name,int8 _number) public { //比如在这里,用memory声明的_name 可以被再次赋值 _name = "cat"; //如果使用calldata 声明 _name, 则上句话会报错 }
那么在 addPerson
的入参中,为什么 _number
不用 memory
或 calldata
修改?
data location
只适用于数组,结构体或映射类型。因为 string
实际上是数组,所以需要用 datalocation
修饰
Mapping
功能同java的map
声明和使用:
//声明一个mapping mapping(string => int8) public nameAndNumber; //使用 function addPerson (string memory _name,int8 _number) public { nameAndNumber[_name] = _number; }
关键词: 动态数组
运行环境
成员函数