solidity高级语法

高级语法

1. 自动推导 var

强烈不建议使用!!

为了方便,并不总是需要明确指定一个变量的类型,编译器会通过第一个向这个对象赋予的值的类型来进行推断

uint24 x = 0x123;
var y = x;
  • 由var引发的血案…

    需要特别注意:由于类型推断是根据第一个变量进行的赋值。所以下面的代码将是一个无限循环,因为一个uint8的i的将小于2000。

for (var i = 0; i < 2000; i++)
{
    //uint8 -> 255
	//无限循环
}
pragma solidity ^0.4.25;

contract Test{
    function Hi() view returns (uint, uint){
        uint count = 0;
        var i = 0;
        for (; i < 257; i++) {
            count++;
            if(count >= 260){
                break;
            }
        }
        return (count, i);
    }
}
/*
结果:
0: uint256: 260
1: uint256: 3

分析:当 循环到 i =255 时,count = 256,再往后 i 又从0开始了!
i   ,  count
255 ,  256
0   ,  257
1   ,  258
2   ,  259
3   ,  260
*/

2.全局函数/变量

2.1 区块和交易的属性
函数含义
block.blockhash(uint blockNumber)哈希值(byte32)
block.coinbase(address) 当前块矿工的地址。
block.difficulty(uint)当前块的难度
block.gaslimit(uint)当前块的gaslimit
block.number(uint)当前区块的块号
block.timestamp(uint)当前块的时间戳
msg.data(bytes)完整的调用数据(calldata)
msg.gas(uint)当前还剩的gas
msg.sender(address)当前调用发起人的地址
msg.sig(bytes4)调用数据的前四个字节(函数标识符)
msg.value(uint)这个消息所附带的货币量,单位为wei
now (uint)当前块的时间戳等同于block.timestamp
tx.gasprice(uint) 交易的gas价格
tx.origin(address)交易的发送者(完整的调用链)
  • 示例:
pragma solidity ^0.4.25;

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 letgo (){
        //给定区块号的哈希值,只支持最近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)交易的发送者(完整的调用链)  
    }
}
2.2 货币单位
  • 一个字面量的数字,可以使用后缀weifinneyszaboether来在不同面额中转换。
  • 不含任何后缀的默认单位是wei。如1 ether == 1000 finney的结果是true
pragma solidity ^0.4.25;

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;
    }
}
2.3 时间单位
  • 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.25;

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;
    }
}

3.事件(Event)

  • 可以用来记录日志
pragma solidity ^0.4.0;

contract ClientReceipt {
    //定义,注意,需要加分号,相当于一句语句,与struct和enum不同。
    event Deposit(
        address indexed _from,
        uint indexed _id,
        uint _value
    );

    function deposit(uint _id) {
        //使用
        Deposit(msg.sender, _id, msg.value);
    }
}

在这里插入图片描述

4.访问函数

  • 编译器为自动为所有的public的状态变量创建访问函数。下面的合约例子中,编译器会生成一个名叫data的无参,返回值是uint的类型的值data。状态变量的初始化可以在定义时完成。
pragma solidity ^0.4.25;

contract C{
    uint public data = 10;
}

contract D{
    C c = new C();
    
    function getDataUsingAccessor() returns (uint){
        return c.data();
    }
}
  • 访问函数有外部(external)可见性。如果通过内部(internal)的方式访问,比如直接访问,你可以直接把它当一个变量进行使用,但如果使用外部(external)的方式来访问,如通过this.,那么它必须通过函数的方式来调用。
pragma solidity ^0.4.25;

contract viewTest{
    uint public c = 10;
    
    function accessInternal() internal view returns (uint){
        return c;
    }
    //合约内部也能够调用用external修饰的函数, 但是要使用外部调用方式this	
    function accessExternal() view external returns (uint){
        return this.c();
    }
}

5.错误处理

传统方法:采用 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.21;

contract HasAnOwner {
    address public owner;
    uint public a ;
    
    constructor() public {
        owner = msg.sender;
    }
    
    function useSuperPowers()  public { 
        require(msg.sender == owner);
        a = 11111;
        /*
        if (msg.sender != owner){
            throw;
        }
        */
        
        a = 10;
       // do something only the owner should be allowed to do
    }
}

6.修饰器(modifier)

修改器(Modifiers)可以用来轻易的改变一个函数的行为。比如用于在函数执行前检查某种前置条件。修改器是一种合约属性,可被继承,同时还可被派生的合约重写(override)。下面我们来看一段示例代码:

pragma solidity ^0.4.21;

contract HasAnOwner {
    address public owner;
    uint public a ;
    
    constructor() public {
        owner = msg.sender;
    }
    
    modifier ownerOnly(address addr) {
        require(addr == owner);
        //代码修饰器所修饰函数的代码
        _;
    }
    
    function useSuperPowers() ownerOnly(msg.sender) public { 
    	//require(addr == owner);
        a = 10;
       // do something only the owner should be allowed to do
    }
}

7.元组 (tuple)

元组是一个数据集合,类似于字典但是无法修改数据,使用圆括号包括多种数据类型。

pragma solidity ^0.4.25;

contract Test {
    
    struct Student {
        string name;
        uint age;
        uint score;
        string sex;
    }
    
    //两种赋值方式
    Student public stu1 = Student("lily", 18, 90, "girl");
    Student public stu2 = Student({name:"Jim", age:20, score:80, sex:"boy"});

    Student[] public Students;
    
    function assign() public {
        Students.push(stu1);
        Students.push(stu2);
        
        stu1.name = "Lily";
    }
    
    //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);
    }
}

8. 内置数学函数

ripemd160

keccak256

addmod

ecrecover

9.继承

  • 继承关键字:is,语法:contract Son is Father{ }
  • 合约 继承 另一个合约 来 达到复用的目的
    • 继承 父合约的所有成员变量(state var - 状态变量)
    • 继承 父合约的所有方法
  • 继承的本质:代码复制,将 父合约 代码复制到 子合约
pragma solidity ^0.4.25;
//父合约
contract Father{
    string public fatherName = "James";
}
//子合约
contract Son is Father{
    string public sonName = "Jun";
    
    function testFather() public{
        fatherName = "James01";
        sonName = "Jun01";
    }
}
  • super和this关键字
    • super 在合约中指向父合约
    • this 在合约中指向本合约
pragma solidity ^0.4.25;
//父合约
contract Father{
    string public fatherName = "James";
    function printName() public view returns(string){
        return fatherName;
    }
}
//子合约
contract Son is Father{
    string public sonName = "Jun";
    
    function testFather() public{
        this.sonName = "Jun01";
        super.fatherName = "James01";
        super.printName();
    }
}
  • 注意:父子同名的成员都会存在,只是访问方式有变化
pragma solidity ^0.4.25;

contract Father{
    string public fatherName = "James";
    function outName() public view returns(string){
        return fatherName;
    }
}

contract Son is Father{
    string public fatherName = "James2";
    string public sonName = "Jun";
    
    function outName() public view returns(string){
        return super.outName();
    }
}
  • 访问 父合约所有的非私有成员 (包括 internal 的函数 和 成员变量)
contract Father{
  uint public stateVar;//成员变量
  //public 方法
  function aPublicFun() public pure returns(string){
      return "publicFunc invoked";
  }
  function aInternalFun() internal pure returns(string){
      return "internalFunc invoked";
  }
  function aExternalFun() external pure returns(string){
      return "externalFunc invoked";
  }
  function aPrivateFun() private pure returns(string){
      return "privateFunc invoked";
  }
}
// 子合约 继承 父合约
contract Son is Father{
  function testFather() public{
    //不能访问`private`
    //aPrivateFun();

    //访问父类的`public`方法
    aPublicFun();

    //访问父类的状态变量
    stateVar = 10;

    //访问父类的`internal`方法
    aInternalFun();
    //访问父类的'external'方法,需要通过this关键字 
    this.aExternalFun();
  }
    
  // 调用某合约访问权限是external的方法
  function testExternal(Father fObj)public view returns(string){
      return fObj.aExternalFun();
  }
}

10.继承中同名成员

问题:如果父合约 与 子合约 中 有 相同名字 的 成员变量 或 方法的话,会怎么样?
答:不管同名与否,父合约所有成员都会被 “继承” 到 子合约中。只是子合约调用时有些区别。

  • 访问就近原则:子合约中 调用 同名成员 都是子合约中的,如:
pragma solidity ^0.4.25;

contract Father{
    string public fatherName = "James";
}

contract Son is Father{
    string public fatherName = "James2";
    
    function outName() public view returns(string){
        return fatherName; // James2
    }
}
  • 父合约与子合约
  • 最远继承原则:在继承链中,由于继承实现是代码复制。如果出现函数名重写,最终使用的是继承链上哪个合约定义的代码呢?实际执行时,依据的是 最远继承原则(most derived)
pragma solidity ^0.4.0;

contract Base1{
  function data() public view returns(uint){
    return 1;
  }
}

contract Base2{
  function data() public view  returns(uint){
    return 2;
  }
}

contract MostDerived1 is Base1, Base2{ // extends Base2 (most derived)
  function call() public view returns(uint){
    return data(); // Base2.data()
  }
}

contract MostDerived2 is Base2, Base1{ // extends Base1 (most derived)
  function call() public view returns(uint){
    return data(); // Base1.data()
  }
}
  • 可以指定某个父合约
pragma solidity ^0.4.0;
contract owned {
    function owned() { owner = msg.sender; }
    address owner;
}

contract mortal is owned {
    event mortalCalled(string);
    function kill() {
        mortalCalled("mortalCalled");
        if (msg.sender == owner) selfdestruct(owner);
    }
}

contract SpecifyBase is mortal {
    event SpecifyBase(string);
    function kill() {
      SpecifyBase("do own cleanup");
      mortal.kill();
    }
}

11.外部调用

外部调用,后面项目会用到

pragma solidity ^0.4.24;


contract C1 {
    uint public num = 10;
    function setValue(uint a) public {
            num = a;
    }
}

//手动赋值
contract C2 {
    C1 c1;
    function call (address addr) public {
        c1 = C1(addr);
        c1.setValue(100);
        
        //addr.setValue(1000); 不允许
    }
}

//合约自动调用
contract C3 {
    C1 c1;
    
    function C3() {
        address  c1Addr = new C1();
        c1 = C1(c1Addr);  
        
        //或者 直接使用C1来承接亦可
        //c1 = new C1();
    }
    
    function getValue() public constant returns(uint) {
        return c1.num();
    }
    
    //注意constant 的坑!!!!,
    //函数加上constant之后,运行修改状态变量,但是修改不会生效,好坑!!!
    function setValue(uint num) public {
        c1.setValue(num);
    }
}

官方示例

pragma solidity ^0.4.0;

contract InfoFeed {
    function info() public payable returns (uint ret) {
        return 42; 
    }
}

contract Consumer {
    InfoFeed feed;
    function setFeed(address addr) public { 
        feed = InfoFeed(addr); 
    }
    
    function callFeed() public { 
        feed.info.value(10).gas(800)(); 
    }
}

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值