本篇将介绍solidity的基础语法
1.1版本杂注
在使用solidity编写合约时,应该使用版本杂注声明使用的编译器版本,这是为了避免该合约在未来被引入不兼容变更的编译器所编译。
版本号形式 “0.x.0” “x.0.0”;
使用语法:
pragma solidity ^0.4.0
1.2 import用法
导入其他源文件
在全局级别,可以使用以下形式的import语句:
import "filename";
上述语句将所有全局符号从filename导入当前全局范围。
import * as symbolName from "filename";
实例:
pragma solidity 0.8.0;
import "https://github.com/0xcert/ethereum-erc721/src/contracts/tokens/nf-token-metadata.sol";
import "https://github.com/0xcert/ethereum-erc721/src/contracts/ownership/ownable.sol";
1.3代码注释
就像任何其他语言一样,Solidity可以使用单行和多行注释。
// This is a single-line comment.
/*
This is a
multi-line comment
*/
1.4数据类型
一般的值类型
布尔类型
关键词:bool
bool 类型的默认值是 false
值是常数,即true或false。
整数类型
关键字:int/uint(uint8到uint256,步长为8(无符号,最多为256位),int8为int256)
各种大小的有符号和无符号整数。
例:
contract MySample{
uint UnsignedInt =50;
}
在上面的语句中,我们创建了一个名为InsignedInt的uint并将其设置为50。
地址类型
关键字:address
保存一个20字节的值(以太坊地址的大小)。地址类型也有members,并作为所有合约的基础。
balance 属性及transfer() 函数
这里是地址类型相关成员的快速索引
balance用来查询账户余额,transfer()用来发送以太币(以wei为单位)
address x = 0x123;
address myAddress = this;
if (x.balance < 10 && myAddress.balance > = 10)
x.transfer(10);
如果x是合约地址,合约的回退函数(fallback 函数)会随transfer调用一起执行(这个是EVM特性),如果因gas耗光或其他原因失败,转移交易会还原并且合约会抛异常停止。
字符串类型
String:字符串文字用双引号或单引号如“foo”或’bar’编写。
用于任意长度的UTF数据。
string language ="Solidity";
这些值类型可以在包含运算符的表达式中相互交互
1.5运算符
Solidity有四种类型的运算符:
算术运算符
Solidity具有非常简单的数学运算。以下与大多数编程语言类似:
增加:x + y
减法:x - y
乘法:x * y
除法:x / y
取整/求余:x%y
Solidity还提供了使用指数运算符的选项,具体如下:
uint x = 10 ** 3; // equal to 10^3 = 1000
增量运算符
增量运算符的稳定性:a++,a- ,++a,-a,a+=1,a=a+1
(a++ 的含义是先赋值后相加,如 b=a++; 先将a的值赋给b,然后a再加上1;++a的含义是先相加后赋值,如 b=++a 先将a加上1,然后再把加上1的a赋给b.)
适用于其他编程语言的规则也是类似的。
按位运算符
1.& 操作数之间转换成二进制之后每位进行与运算操作(同1取1)
2.| 操作数之间转换成二进制之后每位进行或运算操作(有1取1)
3.~ 操作数转换成二进制之后每位进行取反操作(直接相反)
4.^ 操作数之间转换成二进制之后每位进行异或操作(不同取1)
5.<<操作数转换成二进制之后每位向左移动x位的操作
6.>>操作数转换成二进制之后每位向右移动x位的操作
pragma solidity ^0.4.0;
contract helloworld {
function Wyutest(uint8 a,uint8 b) public view returns(uint8){
return a&b;
}
function Whuotest(uint8 a,uint8 b) public view returns(uint8){
return a|b;
}
function Wfantest(uint8 a) public view returns(uint8){
return ~a;
}
function Wyihuotest(uint8 a,uint8 b) public view returns(uint8){
return a^b;
}
function zuoyitest(uint8 a,uint8 b) public view returns(uint8){
return a<<b;
}
function youyitest(uint8 a,uint8 b) public view returns(uint8){
return a>>b;
}
}
逻辑运算符
Solidity中的逻辑运算符:!(逻辑否定),&&(逻辑和),||(逻辑或),==(相等),!=(不相等)
例:
contract operators {
// Arithmetic Operators
// +,-,*,/, %, **
// Incremental Operators
// a++, a--, a+=1, a=a+1,++a,--a;
a=10;
a= a++; //here, output will be 10, because the value is first returned and then then increment is done(这里,输出将是10,因为首先返回值,然后递增)
a=++a;
//Logical Operators
!, &&, ||, ==, !=
isOwner = true && false;
var orValue= 0x02 | 0x01; // output would be 0x03(输出应为0x03)
//Bitwise Operators~,>>, <<;
function Operators() {
// Initialize state variables here(在此初始化状态变量)}}
1.6数据结构
solidity数据结构
Solidity提供三种类型的数据结构:
结构Structs
Solidity提供了一种以Structs形式定义新类型的方法。Structs是自定义类型,可以对多个变量进行分组。
pragma solidity ^0.4.0;
contract Ballot {
struct Voter { // Struct
uint weight1, weight2, weight3;
bool voted;
address delegate1, delegate2, delegate3, delegate4;
string name;
uint vote1, vote2, vote3, vote4, vote5;
uint height1, height2, height3 } }
注意:结构只能有16个成员,超过该成员可能会发生以下错误:Stack too Deep 堆栈太深。
结构允许创建具有多个属性的更复杂的数据类型。
数组Arrays
Solidity中的数组可以具有编译时固定大小,也可以是动态的。
uint[3] fixed; //array of fixed length 3(固定长度的数组3)
uint[] dynamic; //a dynamic array has no fixed size, it can keep growing(动态数组没有固定的大小,它可以不断增长)
还可以创建一个结构数组。使用以前创建的Voter结构:
Voter[] voting;
注意:将数组声明为public将自动为其创建getter方法。
Voter[] public voting;
映射mappings
映射可以看作是哈希表,它们被虚拟地初始化,使得每个可能的键都存在并被映射到其字节表示全为零的值:类型的默认值。
映射声明为:
Mapping(_Keytype => _ValueType )
注意:_Keytype几乎可以是任何类型,除了动态大小的数组,合约,枚举和结构。
在区块链当中,不同的地址发出某个请求的时候合约往往需要辨识它是否拥有请求的权利。在这里我们就可以通过一个地址-权利(bool)的映射来调用这个地址对应的权利,判断是否完成请求。
我会写一个示例合约来讲解如何使用一个映射管理权限和设置权限。
pragma solidity >=0.4.22 <0.6.0;
contract Authentication
{
mapping(address=>bool) Auth_list;
function set_allow(address allow_address) public {
Auth_list[allow_address] = true;
}
function set_deny(address deny_address) public {
Auth_list[deny_address] = false;
}
function query_auth(address target_address) public view returns(bool){
if(Auth_list[target_address]==true)
{
return true;
}
else
{
return false;
}
}
}
首先我们创建一个映射变量Auth_list,用于储存地址以及它对应的权限,权限的代表为true和false。
接着我们通过两个函数来对地址的权限进行设置,分别是set_allow和set_deny,输入的参数为对应的地址,在执行了这个函数之后就会将这个地址的权限保存到这个合约的Auth_list当中。
这里有几点需要注意:
1.调用这两个函数都需要花费gas,因为更改了存储在区块链上的内存。
2.这个函数的权限可以通过modifier设置,指定为特定的人或者白名单,这个后面会讲到。
最后,我们可以通过query_auth来查询这个合约当中不同地址的访问权限,获得一个公开透明可查询的结果。
控制结构
除了switch和goto之外,JavaScript中的大多数控制结构都在Solidity中可用。
所以有:if,else,while,do,for,break,continue,return,?:,使用从C或JavaScript中已知的通常语义。
注意:没有像C和JavaScript那样从非布尔类型到布尔类型的类型转换。
现在让我们看看这些控制结构如何在Solidity中使用。
contract ControlStructure {
address public a;
function ControlStructure>){
// if-else can be used like this(if-else可以这样使用)
if(input1==2)
a=1;
else
a=0;
// while can be used like this(while 可以像这样使用)
while(input1>=0){
if(input1==5)
continue;
input1=input1-1;
a++;}
// for loop can be used like this(for循环可以这样使用)
for(uint i=0;i<=50;i++) { a++; if(a==4) break; } //do while can be used like this do(do while可以像这样使用) { a--; } (while a>0);
// Conditional Operator can be used like this(条件运算符可以这样使用)
bool IsTrue = (a == 1)?true: false;
/*will show an error because
there is no type conversion from non-boolean to boolean(将显示错误,因为
没有从非布尔值到布尔值的类型转换)
*/
if(1)
{
}