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

 

12-21 20:56