3高级语法
自动推导类型
为了方便,并不总是需要明确指定一个变量的类型,编译器会通过第一个向这个对象赋予的值的类型来进行推断.
例如:
uint24 x = 0x123; var y = x;
需要特别注意的是,由于类型推断是根据第一个变量进行的赋值。所以下面的代码将是一个无限循 环,因为⼀一个uint8的i的将小于2000。
for (var i = 0; i < 2000; i++) { //uint8 -> 255 //越界归0 //无限循环 }
全局变量/函数
区块和交易的属性:
代码:
pragma solidity ^0.4.24;
contract Test {
bytes32 public blockhash;
address public coinbase;
uint public difficulty;
uint public gaslimit;
uint public blockNum;
uint public timestamp;
bytes public calldata;
uint public gas;
address public sender;
bytes4 public sig;
uint public msgValue;
uint public now;
uint public gasPrice;
address public txOrigin;
function tt (){
//给定区块号的哈希值,只支持最近256个区块,且不包含当前区块
blockhash = block.blockhash(block.number - 1);
coinbase = block.coinbase ;//当前块矿工的地址。
difficulty = block.difficulty;//当前块的难度。
gaslimit = block.gaslimit;// (uint)当前块的gaslimit。
blockNum = block.number;// (uint)当前区块的块号。
timestamp = block.timestamp;// (uint)当前块的时间戳。
calldata = msg.data;// (bytes)完整的调⽤用数据(calldata)。
gas = msg.gas;// (uint)当前还剩的gas。
sender = msg.sender; // (address)当前调用发起人的地址。
sig = msg.sig;// (bytes4)调用数据的前四个字节(函数标识符)。
msgValue = msg.value;// (uint)这个消息所附带的货币量,单位为wei。
now = now;// (uint)当前块的时间戳,等同于block.timestamp
gasPrice = tx.gasprice;// (uint) 交易的gas价格。
txOrigin = tx.origin;// (address)交易的发送者(完整的调用链)
}
}
货币单位
⼀一个字面量的数字,可以使用后缀 wei , finney , szabo 或 ether 来在不同面额中转换; 不含任何后缀的默认单位是 wei 。如1 ether == 1000 finney 的结果是 true 。
代码:
pragma solidity ^0.4.24;
contract EthUnit{
uint a = 1 ether;
uint b = 10 ** 18 wei;
uint c = 1000 finney;
uint d = 1000000 szabo;
function f1() constant public returns (bool){
return a == b;
}
function f2() constant public returns (bool){
return a == c;
}
function f3() constant public returns (bool){
return a == d;
}
function f4() constant public returns (bool){
return 1 ether == 100 wei;
}
}
时间单位
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
代码:
pragma solidity ^0.4.24;
contract TimeUnit{
function f1() pure public returns (bool) {
return 1 == 1 seconds;
}
function f2() pure public returns (bool) {
return 1 minutes == 60 seconds;
}
function f3() pure public returns (bool) {
return 1 hours == 60 minutes;
}
function f4() pure public returns (bool) {
return 1 days == 24 hours;
}
function f5() pure public returns (bool) {
return 1 weeks == 7 days;
}
function f6() pure public returns (bool) {
return 1 years == 365 days;
}
}
事件(event)
pragma solidity ^0.4.24;
contract evnetTest{
mapping(address=>uint256)public personToMoney;
//定义一个时间事件,时间事件是一个语句,在后面要加分号,与结构体不同;
/*
1.定义一个时间事件,使用圆括号,后面加分号
2.使用emit关键字
3.在web3调用时可以监听到事件
4.相当于日志
*/
event playEnent(address,uint256,uint256);
function paly()public payable
{
require(msg.value==100);
personToMoney[msg.sender]=msg.value;
//emit:关键字表示发射时间;出发触发事件
emit playEnent(msg.sender,msg.value,block.timestamp);
}
function getBalance()public view returns(uint256){
return address(this).balance;
}
}
结果:
访问函数
-编译器为自动为所有的 public的状态变量 创建访问函数。下面的合约例子中,编译器会生成一个名叫data的无参,返回值是uint的类型的值data。状态变量的初始化可以在定义时完成。
-访问函数有外部(external)可见性。如果通过内部(internal)的方式访问,比如直接访问,你可以直接把它当一个变量进行使用,但如果使用外部(external)的方式来访问,如通过this.,那么它必须通过函数的方式来调用。
1.加public的常态变量,solidity会自动的生成一个同名的访问函数
2.在合约内部使用这个状态变量的时候,直接当变量使用即可
3.在合约外部访问这个public变量(data ),就需要使用xx .data()形式
代码:
pragma solidity ^0.4.24;
contract test {
uint256 public data =200;
function getData()public view returns(uint256){
return data;
}
//this 代表合约本身,如果在合约内部使用this自身的方法的话,相当于外部调用
function getData1()public view returns(uint256){
return this.data();
}
}
contract test1{
function getData()public returns(uint256){
test t=new test();
return t.data();
}
}
修饰器
程序运行流程
修改器(Modifiers)可以用来轻易的改变一个函数的行为。⽐比如⽤用于在函数执行前检查某种前置条件。 修改器是一种合约属性,可被继承,同时还可被派生的合约重写(override)。下面我们来看一段示例代 码:
1.可以传递参数
2._;
3.放到是函数后面
pragma solidity ^0.4.24;
contract ModifyTest{
uint256 public value;
address public owner;
//构造函数
constructor()public{
owner=msg.sender;
}
//修饰器其器器,可以进行传参
modifier onlyOwner{
require(msg.sender==owner);
//_;表示这个修饰其器所修饰的函数代码
_;
}
//使用修饰器,在将仅管理员可以执行的限定放到函数外面
function changeValue(uint256 _value)onlyOwner public{
//传参,一般前面加下滑县
value=_value;
}
}
错误处理
传统方法:采用 throw 和 if ... throw 模式(已过时),例如合约中有一些功能,只能被授权为拥有者的 地址才能调用
if(msg.sender != owner) { throw; }
等价于如下任意一种形式:
if(msg.sender != owner) { revert(); } assert(msg.sender == owner); require(msg.sender == owner);
代码:
pragma solidity ^0.4.24;
contract HasAnOwner {
address public owner;
uint public a ;
constructor() public {
owner = msg.sender;
}
function useSuperPowers() public {
require(msg.sender == owner);
/*
if (msg.sender != owner){
throw;
}
*/
a = 10;
// do something only the owner should be allowed to do
}
}
合约
合约的创建:
pragma solidity ^0.4.24;
contract C1{
uint256 public value;
constructor (uint256 _input)public{
value=_input;
}
function getValue()public pure returns(uint256){
return 100;
}
}
contract C2{
C1 public c1;
C1 public c11;
function getValue1()public returns(uint256){
//创建一个合约,返回一个地址
address addr=new C1(10 );
// 地址需要显示的转换为特定类型,才可以正常使用
c1= C1(addr);
return c1.getValue();
}
function getValue2()public returns(uint256){
//定义的时候,同时完成转换
c11=new C1(20 );
return c11.getValue();
}
C1 public c13;
function getValue3(address _addr)public returns(uint256){
//当传入地址是时,需要显示的转换,否则不可以用
c13=C1(_addr);
return c13.getValue();
}
}
合约继承 is关键字;最远继承
pragma solidity ^0.4.0;
contract Base1{
function data() pure returns(uint){
return 1;
}
}
contract Base2{
function data() pure returns(uint){
return 2;
}
}
//继承base2的data方法
contract MostDerived1 is Base1, Base2{ }
//继承base1的data方法
contract MostDerived2 is Base2, Base1{
}
可以指定某个父合约
pragma solidity ^0.4.0;
contract Base1{
function data() pure returns(uint){
return 1;
}
}
contract Base2{
function data() pure returns(uint){
return 2;
}
}
contract MostDerived1 is Base1, Base2{
function mydata() pure returns(uint){
return Base1.data();
}
}
contract MostDerived2 is Base2, Base1{
function mydata() pure returns(uint){ return Base2.data();
}
}
外部调用
pragma solidity ^0.4.24;
contract InfoFeed{
function info()public payable returns(uint256 ret){
return 42;
}
function getBalance()public view returns(uint256){
return address(this).balance;
}
}
contract Consumer{
InfoFeed feed;
function setFeed(address addr)public{
feed=InfoFeed(addr);
}
function callFeed()public{
//给Info合约转账10wei ,汽油费上线上限800
//合约转账语法
feed.info.value(10).gas(800)();
}
function()payable public{
}
function getBalance()public view returns(uint256){
return address(this).balance;
}
}
元祖
return(a, b, c) solidity无法返回自定义的数据结构,所以若想返回一个自定义结构的数据,需要在函数中一次返回多个值,即元组。元组是一个数据集合,类似于字典但是无法修改数据,使用圆括号包括多种数据类型。
//1. 返回⼀一个Student结构
function getLily() public view returns(string, uint, uint, string)
{
Student memory lily = Students[0];
return (lily.name, lily.age, lily.score, lily.sex);
}
}
内置数学函数
ripemd160,keccak256,addmod,ecrecover
代码:
pragma solidity ^0.4.24;
contract operation{
function Hash()public pure returns(bytes32){
//先编码。后运算
bytes memory v1=abi.encodePacked("hello",uint256(1),"world");
return keccak256(v1);
}
function Test()public pure returns(bytes32){
bytes32 hash=sha3("hello",uint256(1),"world");//以前的用法,不推荐使用了,和keccak256效果一样
return keccak256("hello",uint256(1),"world");
}
}
delete
delete操作符可以用于任何变量量,将其设置成默认值 如果对动态数组使用delete,则删除所有元素,其长度变为0 如果对静态数组使用delete,则重置所有索引的值
1.new 创建对象、合约
2.delete操作符可以用于任何变量,将其设置为默认值
3.如果对动态数组使用delete,删除所有的元素,其长度变为零
4.如果读静态数组使用delete,则重置所有的索引值(根据元素类型)
5.如果对map 类型使用delete,什么都不会发生
6.但如果对map 类型中的一个兼职键值使用delete,则删除与该键相关的值
pragma solidity ^0.4.24;
contract Delet{
//1.string
string public str ="hello";
function deleteDtring()public{
//删除之后n便变为0
delete str;
}
//2.array,对于固定长度的数组。则会想删除每个元素的值,但是数组的元素不变
int256[10] public arr=[1,2,3,4,5];
function deleteFixArray()public{
delete arr;
}
//3.array new
uint256[] arr1=new uint256[](10);
function setArray()public{
for (uint256 i=0; i< arr1.length; i++){
arr1[i]=i;
}
}
function deleteArray()public{
delete arr1;
}
function getArray()public view returns(uint256[]){
return arr1;
}
//mapping
mapping(uint256=>string)m1;
function setMaping()public{
m1[1]="hello";
m1[2]="world";
}
function deleteMapping()public{
//delete m1;不允许,只能删除键值内容
delete m1[1];
}
function getMapping(uint256 _index)public view returns(string){
return m1[_index];
}
}
补充:被internal修饰的函数,可以被内部合约调用,也可以被子合约调用,外部合约无法调用
ECR20:代币编写规范 推荐:https://www.jianshu.com/p/a5158fbfaeb9