3高级语法
自动推导类型
为了方便,并不总是需要明确指定一个变量的类型,编译器会通过第一个向这个对象赋予的值的类型来进行推断.
例如:
uint24 x = 0x123; var y = x;
需要特别注意的是,由于类型推断是根据第一个变量进行的赋值。所以下面的代码将是一个无限循 环,因为⼀一个uint8的i的将小于2000。
for (var i = 0; i < 2000; i++) { //uint8 -> 255 //越界归0 //无限循环 }
全局变量/函数
区块和交易的属性:
代码:

1 pragma solidity ^0.4.24; 2 contract Test { 3 4 bytes32 public blockhash; 5 address public coinbase; 6 uint public difficulty; 7 uint public gaslimit; 8 uint public blockNum; 9 uint public timestamp; 10 bytes public calldata; 11 uint public gas; 12 address public sender; 13 bytes4 public sig; 14 uint public msgValue; 15 uint public now; 16 uint public gasPrice; 17 address public txOrigin; 18 19 function tt (){ 20 //给定区块号的哈希值,只支持最近256个区块,且不包含当前区块 21 blockhash = block.blockhash(block.number - 1); 22 coinbase = block.coinbase ;//当前块矿工的地址。 23 difficulty = block.difficulty;//当前块的难度。 24 gaslimit = block.gaslimit;// (uint)当前块的gaslimit。 25 blockNum = block.number;// (uint)当前区块的块号。 26 timestamp = block.timestamp;// (uint)当前块的时间戳。 27 calldata = msg.data;// (bytes)完整的调⽤用数据(calldata)。 28 gas = msg.gas;// (uint)当前还剩的gas。 29 sender = msg.sender; // (address)当前调用发起人的地址。 30 sig = msg.sig;// (bytes4)调用数据的前四个字节(函数标识符)。 31 msgValue = msg.value;// (uint)这个消息所附带的货币量,单位为wei。 32 now = now;// (uint)当前块的时间戳,等同于block.timestamp 33 gasPrice = tx.gasprice;// (uint) 交易的gas价格。 34 txOrigin = tx.origin;// (address)交易的发送者(完整的调用链) 35 } 36 } 37
货币单位
⼀一个字面量的数字,可以使用后缀 wei , finney , szabo 或 ether 来在不同面额中转换; 不含任何后缀的默认单位是 wei 。如1 ether == 1000 finney 的结果是 true 。
代码:
1 pragma solidity ^0.4.24; 2 contract EthUnit{ 3 uint a = 1 ether; 4 uint b = 10 ** 18 wei; 5 uint c = 1000 finney; 6 uint d = 1000000 szabo; 7 function f1() constant public returns (bool){ 8 return a == b; 9 } 10 11 function f2() constant public returns (bool){ 12 return a == c; 13 } 14 15 function f3() constant public returns (bool){ 16 return a == d; 17 } 18 19 function f4() constant public returns (bool){ 20 return 1 ether == 100 wei; 21 } 22 }
时间单位
seconds,minutes,hours,days,weeks,years均可做为后缀,默认是seconds为单位。 1 = 1 seconds 1 minutes = 60 seconds 1 hours = 60 minutes 1 days = 24 hours 1 weeks = 7 days 1 years = 365 days
代码:
1 pragma solidity ^0.4.24; 2 contract TimeUnit{ 3 function f1() pure public returns (bool) { 4 return 1 == 1 seconds; 5 } 6 7 function f2() pure public returns (bool) { 8 return 1 minutes == 60 seconds; 9 } 10 11 function f3() pure public returns (bool) { 12 return 1 hours == 60 minutes; 13 } 14 15 function f4() pure public returns (bool) { 16 return 1 days == 24 hours; 17 } 18 19 function f5() pure public returns (bool) { 20 return 1 weeks == 7 days; 21 } 22 function f6() pure public returns (bool) { 23 return 1 years == 365 days; 24 } 25 } 26
事件(event)
1 pragma solidity ^0.4.24; 2 contract evnetTest{ 3 mapping(address=>uint256)public personToMoney; 4 //定义一个时间事件,时间事件是一个语句,在后面要加分号,与结构体不同; 5 /* 6 1.定义一个时间事件,使用圆括号,后面加分号 7 2.使用emit关键字 8 3.在web3调用时可以监听到事件 9 4.相当于日志 10 */ 11 event playEnent(address,uint256,uint256); 12 13 function paly()public payable 14 { 15 require(msg.value==100); 16 personToMoney[msg.sender]=msg.value; 17 18 //emit:关键字表示发射时间;出发触发事件 19 emit playEnent(msg.sender,msg.value,block.timestamp); 20 } 21 22 function getBalance()public view returns(uint256){ 23 return address(this).balance; 24 } 25 }
结果:
访问函数
-编译器为自动为所有的 public的状态变量 创建访问函数。下面的合约例子中,编译器会生成一个名叫data的无参,返回值是uint的类型的值data。状态变量的初始化可以在定义时完成。
-访问函数有外部(external)可见性。如果通过内部(internal)的方式访问,比如直接访问,你可以直接把它当一个变量进行使用,但如果使用外部(external)的方式来访问,如通过this.,那么它必须通过函数的方式来调用。
1.加public的常态变量,solidity会自动的生成一个同名的访问函数
2.在合约内部使用这个状态变量的时候,直接当变量使用即可
3.在合约外部访问这个public变量(data ),就需要使用xx .data()形式
代码:
1 pragma solidity ^0.4.24; 2 3 contract test { 4 uint256 public data =200; 5 function getData()public view returns(uint256){ 6 return data; 7 } 8 9 //this 代表合约本身,如果在合约内部使用this自身的方法的话,相当于外部调用 10 function getData1()public view returns(uint256){ 11 return this.data(); 12 } 13 } 14 contract test1{ 15 function getData()public returns(uint256){ 16 test t=new test(); 17 return t.data(); 18 } 19 } 20 21 22
修饰器
程序运行流程
修改器(Modifiers)可以用来轻易的改变一个函数的行为。⽐比如⽤用于在函数执行前检查某种前置条件。 修改器是一种合约属性,可被继承,同时还可被派生的合约重写(override)。下面我们来看一段示例代 码:
1.可以传递参数
2._;
3.放到是函数后面

1 pragma solidity ^0.4.24; 2 3 contract ModifyTest{ 4 uint256 public value; 5 address public owner; 6 //构造函数 7 constructor()public{ 8 owner=msg.sender; 9 } 10 11 //修饰器其器器,可以进行传参 12 modifier onlyOwner{ 13 require(msg.sender==owner); 14 //_;表示这个修饰其器所修饰的函数代码 15 _; 16 17 } 18 19 //使用修饰器,在将仅管理员可以执行的限定放到函数外面 20 function changeValue(uint256 _value)onlyOwner public{ 21 //传参,一般前面加下滑县 22 value=_value; 23 } 24 } 25
错误处理
传统方法:采用 throw 和 if ... throw 模式(已过时),例如合约中有一些功能,只能被授权为拥有者的 地址才能调用
if(msg.sender != owner) { throw; }
等价于如下任意一种形式:
if(msg.sender != owner) { revert(); }
assert(msg.sender == owner);
require(msg.sender == owner);
代码:

1 pragma solidity ^0.4.24; 2 contract HasAnOwner { 3 address public owner; 4 uint public a ; 5 constructor() public { 6 owner = msg.sender; 7 } 8 9 function useSuperPowers() public { 10 require(msg.sender == owner); 11 /* 12 if (msg.sender != owner){ 13 throw; 14 } 15 */ 16 17 a = 10; 18 // do something only the owner should be allowed to do 19 } 20 }
合约
合约的创建:
1 pragma solidity ^0.4.24; 2 3 contract C1{ 4 uint256 public value; 5 constructor (uint256 _input)public{ 6 value=_input; 7 } 8 function getValue()public pure returns(uint256){ 9 return 100; 10 } 11 12 } 13 contract C2{ 14 C1 public c1; 15 C1 public c11; 16 function getValue1()public returns(uint256){ 17 //创建一个合约,返回一个地址 18 address addr=new C1(10 ); 19 // 地址需要显示的转换为特定类型,才可以正常使用 20 c1= C1(addr); 21 return c1.getValue(); 22 23 } 24 25 function getValue2()public returns(uint256){ 26 //定义的时候,同时完成转换 27 c11=new C1(20 ); 28 return c11.getValue(); 29 } 30 31 C1 public c13; 32 function getValue3(address _addr)public returns(uint256){ 33 //当传入地址是时,需要显示的转换,否则不可以用 34 c13=C1(_addr); 35 return c13.getValue(); 36 } 37 }
合约继承 is关键字;最远继承
1 pragma solidity ^0.4.0; 2 3 contract Base1{ 4 5 function data() pure returns(uint){ 6 7 return 1; 8 9 } 10 11 } 12 13 contract Base2{ 14 15 function data() pure returns(uint){ 16 17 return 2; 18 19 } 20 21 } 22 23 //继承base2的data方法 24 25 contract MostDerived1 is Base1, Base2{ } 26 27 //继承base1的data方法 28 29 contract MostDerived2 is Base2, Base1{ 30 31 } 32 33 可以指定某个父合约 34 35 pragma solidity ^0.4.0; 36 37 contract Base1{ 38 39 function data() pure returns(uint){ 40 41 return 1; 42 43 } 44 45 } 46 47 contract Base2{ 48 49 function data() pure returns(uint){ 50 51 return 2; 52 53 } 54 55 } 56 57 contract MostDerived1 is Base1, Base2{ 58 59 function mydata() pure returns(uint){ 60 61 return Base1.data(); 62 63 } 64 65 } 66 67 contract MostDerived2 is Base2, Base1{ 68 69 function mydata() pure returns(uint){ return Base2.data(); 70 71 } 72 73 }
外部调用

1 pragma solidity ^0.4.24; 2 3 contract InfoFeed{ 4 5 function info()public payable returns(uint256 ret){ 6 return 42; 7 } 8 function getBalance()public view returns(uint256){ 9 return address(this).balance; 10 } 11 } 12 13 contract Consumer{ 14 InfoFeed feed; 15 function setFeed(address addr)public{ 16 feed=InfoFeed(addr); 17 } 18 function callFeed()public{ 19 //给Info合约转账10wei ,汽油费上线上限800 20 //合约转账语法 21 feed.info.value(10).gas(800)(); 22 } 23 24 function()payable public{ 25 26 } 27 28 function getBalance()public view returns(uint256){ 29 return address(this).balance; 30 } 31 }
元祖
return(a, b, c) solidity无法返回自定义的数据结构,所以若想返回一个自定义结构的数据,需要在函数中一次返回多个值,即元组。元组是一个数据集合,类似于字典但是无法修改数据,使用圆括号包括多种数据类型。

1 //1. 返回⼀一个Student结构 2 function getLily() public view returns(string, uint, uint, string) 3 { 4 Student memory lily = Students[0]; 5 return (lily.name, lily.age, lily.score, lily.sex); 6 } 7 }
内置数学函数
ripemd160,keccak256,addmod,ecrecover
代码:

1 pragma solidity ^0.4.24; 2 3 contract operation{ 4 function Hash()public pure returns(bytes32){ 5 //先编码。后运算 6 bytes memory v1=abi.encodePacked("hello",uint256(1),"world"); 7 return keccak256(v1); 8 } 9 10 function Test()public pure returns(bytes32){ 11 bytes32 hash=sha3("hello",uint256(1),"world");//以前的用法,不推荐使用了,和keccak256效果一样 12 return keccak256("hello",uint256(1),"world"); 13 } 14 }
delete
delete操作符可以用于任何变量量,将其设置成默认值 如果对动态数组使用delete,则删除所有元素,其长度变为0 如果对静态数组使用delete,则重置所有索引的值
1.new 创建对象、合约
2.delete操作符可以用于任何变量,将其设置为默认值
3.如果对动态数组使用delete,删除所有的元素,其长度变为零
4.如果读静态数组使用delete,则重置所有的索引值(根据元素类型)
5.如果对map 类型使用delete,什么都不会发生
6.但如果对map 类型中的一个兼职键值使用delete,则删除与该键相关的值

1 pragma solidity ^0.4.24; 2 contract Delet{ 3 //1.string 4 string public str ="hello"; 5 function deleteDtring()public{ 6 //删除之后n便变为0 7 delete str; 8 } 9 10 //2.array,对于固定长度的数组。则会想删除每个元素的值,但是数组的元素不变 11 int256[10] public arr=[1,2,3,4,5]; 12 function deleteFixArray()public{ 13 delete arr; 14 } 15 16 //3.array new 17 uint256[] arr1=new uint256[](10); 18 function setArray()public{ 19 for (uint256 i=0; i< arr1.length; i++){ 20 arr1[i]=i; 21 } 22 23 } 24 function deleteArray()public{ 25 delete arr1; 26 27 } 28 function getArray()public view returns(uint256[]){ 29 return arr1; 30 } 31 32 //mapping 33 mapping(uint256=>string)m1; 34 function setMaping()public{ 35 m1[1]="hello"; 36 m1[2]="world"; 37 } 38 function deleteMapping()public{ 39 //delete m1;不允许,只能删除键值内容 40 41 delete m1[1]; 42 } 43 function getMapping(uint256 _index)public view returns(string){ 44 return m1[_index]; 45 } 46 }
补充:被internal修饰的函数,可以被内部合约调用,也可以被子合约调用,外部合约无法调用
ECR20:代币编写规范 推荐:https://www.jianshu.com/p/a5158fbfaeb9