BlockChain入门-Solidity基础语法

01-入门

1
2
3
4
pragma solidity ^0.8.21
contract HelloWeb3{
string public _string="Hello Web3!";
}

第一行注释不写会出现警告。

第二行指编译器版本不允许小于0.8.21,“^”表示不允许编译器版本大于等于0.9.0。

第三行创建string型变量_string

02-变量类型

1
2
3
4
5
6
7
int uint uint256
string bool
address //20字节
address payable
byte32 byte8 byte1
! && || == !=
//&&运算符短路

03-函数

关键字pure标记的函数不能读写链上状态,不消耗gas fee。

1
2
3
function addPure(uint256 _number)external pure returns(uint256 new_number){
new_number=_number+1;
}

关键字view只能读不能改写,不消耗gas fee。

1
2
3
function addView()external view returns(uint256 new_number){
new_number=number+1;
}

关键字internal标记的函数只能被该合约内其他函数调用,不能被外界调用。

1
2
3
function minus()internal{
number=number-1;
}

关键字external标记的函数只能在该合约外被调用,不能被该合约内其他函数调用:

1
2
3
function minusCall()external{
minus();
}

关键字payable标记的函数能够接受Remix的“VALUE”的转账。

1
2
3
4
function minusPayable()external payable returns(uint256 balance){
minus();
balance=address(this).balance; //返回当前合约的余额
}

关键字public标记的函数从内部和外部都可见,private只能从内部访问且继承的合约也不能使用。

04-函数输出

多个返回值:

1
2
3
function returnMultiple()public pure returns(uint256,bool,uint256[3] memory){
return(1,true,[uint256(1),2,5]);
}

命名式返回,仍可用return

1
2
3
4
5
function returnNamed()public pure returns(uint256 _number,bool _bool,uint256[3] memory _array){
_number=2;
_bool=false;
_array=[uint256(3),2,1];
}

解构式赋值:

1
2
3
4
5
6
uint256 _number;
bool _bool;
uint256[3] memory _array;
(_number,_bool,_array)=returnNamed();
//不读的留空
(,_bool,)=returnNamed();

05-变量数据存储和作用域(未完)

数据位置:

storage:默认状态,存储在链上,消耗gas fee多。

memory:函数的参数和临时变量一般用这个,存储在内存中,不上链,消耗gas fee少。当string、bytes、array和自定义结构等返回数据类型变长的情况下必须加memory

calldata:存储在内存中,不上链,不能修改,一般用于函数参数。

1
2
3
function fCalldata(uint[] calldata _x)public pure returns(uint[] calldata){
return(_x);
}

当状态变量storage赋值给本地storage时,以及memory赋值给memory时,会创建引用,类似指针。其他情况均创建副本。

1
2
3
4
5
uint[] x=[1,2,3];
function fStorage()public{
uint[] storage xStorage=x;
xStorage[0]=100; //状态变量x[0]也被同时更改
}

常见全局变量:

address payable msg.sender表示消息发送者,即当前的调用者。

06-引用类型、数组、结构体

数组:

1
2
3
4
5
6
7
8
9
10
11
12
//固定长度数组
uint[8] array1;
bytes1[5] array2;
address[100] array3;
//可变长度/动态数组
uint[] array4;
bytes1[] array5;
address[] array6;
bytes array7; //特殊 bytes本身就是数组 比bytes1[]省gas fee
//memory动态数组 声明长度后不能更改
uint[] memory array8=new uint[](5);
bytes memory array9=new bytes(9);

数组字面常数:

1
2
3
4
5
6
7
8
contract C{
function f()public pure{
g([uint(1),2,3]); //所有元类型与第一个元素为准
}
function g(uint[3] memory _data)public pure{
//...
}
}

创建动态数组时需要一个个元素赋值:

1
2
3
4
uint[] memory x=new uint[](3);
x[0]=1;
x[1]=3;
x[2]=4;

数组成员:

1
2
3
4
a.length; //返回数组长度
a.push(); //动态数组专有 最后添加一个0 并返回该元素的引用
a.push(x); //动态数组专有 最后添加一个x
a.pop(); //动态数组专有 移出数组最后一个元素

结构体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct Student{
uint256 id;
uint256 score;
}
Student student;
function initStudent1()external{
Student storage _student=student;
_student.id=11;
_student.score=100;
}
function initStudent2()external{
student.id=1;
student.score=80;
}
function initStudent3()external{
student=Student(3,90);
}
function initStudent4()external{
student=Student({id:4,score:60});
}

09-常数

const必须在声明的时候初始化,之后不能改变。immutable可以在声明时和构造函数中初始化。

1
2
uint256 constant CONSTANT_NUM=10;
uint256 public immutable IMMUTABLE_NUM=9999999999;

10-控制流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function ifElseTest(uint256 _number)public pure returns(bool){
if(_number==0){
return(true);
}
else{
return(false);
}
}
function forLoopTest()public pure returns(uint256){
uint sum=0;
for(uint i=0;i<10;i++){
sum+=i;
}
return(sum);
}
function whileTest()public pure returns(uint256){
uint sum=0;
uint i=0;
while(i<10){
sum+=i;
i++;
}
return(sum);
}
function doWhileTest()public pure returns(uint256){
uint sum=0;
uint i=0;
do{
sum+=i;
i++;
}while(i<10);
return(sum);
}
function ternaryTest(uint256 x,uint256 y)public pure returns(uint256){
return x>=y?x:y;
}
//存在continue和break关键字

11-构造函数&修饰器(未完)

1
2
3
4
5
6
7
modifier onlyOwner{
require(msg.sender==owner); //检查调用者地址是否为owner
_; //是的话继续运行函数主体,否则报错并revert交易
}
function changeOwner(address _newOwner)external onlyOwner{
owner=_newOwner; //只有owner地址运行这个函数并改变owner
}

12-事件(未完)

事件声明与释放:

1
2
3
4
5
6
7
event Transfer(address indexed from,address indexed to,uint256 value); //定义Transfer事件
function _transfer(address from,address to,uint256 amount)external{
_balances[from]=10000000; //给转账地址一些初始代币
_balances[from]-=amount; //from地址减去转账数量
_balances[to]+=amout; //to地址加上转账数量
emit Transfer(from,to,amount); //释放事件
}