Solidity基础语法

Solidity

Solidity是编写智能合约的语言,运行在ethereum虚拟机上。语法类似于JS,它拥有异常机制,一旦出现异常,所有的执行都会被撤回,这是为了保证合约执行的原子性,避免中间状态出现的数据不一致。

官方提供了IDE: remix
下面看一个简单的合约的例子:

pragma solidity ^0.4.9;
contract Helloworld {
    function multi(uint a, uint b) returns (uint c) {
    uint result = a * b;
    return result;
    }
}

上面这个函数很简单,调用multi方法进行乘法运算。

基础语法

1.数据类型

  • address 以太坊地址的长度,20个字节
  • int/uint 变长的有符号或无符号整型。支持以8递增,uint8到uint256。uint 默认为uint256。
  • bool 布尔型
  • mapping 键值对映射关系,如mapping(address => uint)
  • struct 结构体,如下例子


2.状态变量storage和局部变量memory

两者区别很容易理解,memory可以理解为临时变量,不会记录在链上,而storage是永久存储的。

  • 变量定义时默认为storage,而作为函数参数时,默认为memory
contract HelloWorld{
    
    //等价于 string storage public a;
    string public a;

    //参数等价于string memory _a
    function changeNum(string _a){
    }
    
    
}

  • 当函数参数为memory类型时,相当于值传递,storage才是指针传递
contract HelloWorld2{
    
    string public a;
    
    function HelloWorld2(){
        a = "abc";
    }
    
    
    function f(){
        changeNum(a);
    }
    
    function changeNum(string _a){
        bytes(_a)[0] = "d";
      //由于_a默认为memory,所以_a只是值传递,所以此时修改a的值是不成功的,输出还是abc
      //需要把函数参数修改为string storage _a,才能输出dbc
    }
}

  • 将变量赋值给一个新变量时,新变量的类型由赋值给它的类型决定。
function changeNum(string _a){
        //_a默认为memory类型,所以b也为memory
        string b = _a;
        bytes(_a)[0] = "d";
    }

3.函数四种访问权限

函数声明有public、private、internal和external四种访问权限

  • 1.函数默认声明为public,即可以以internal方式调用,也可以通过external方式调用。可以理解为能够被内部合约访问和外部合约访问。
  • 2.Internal声明的只允许通过internal方式调用,不能被外部合约。而external能够被外部合约访问。
  • 3.private和internal类似,都不能被外部合约访问,唯一的不同是private函数不能被子类调用,而internal可以。

如下例子:

contract FunctionTest{
    
    function publicFunc() {}

    function callFunc(){
        //以`internal`的方式调用函数
        publicFunc();
        
        //以`external`的方式调用函数
        this.publicFunc();
    }
    
    function internalFunc() internal{}
    
    function externalFunc() external{}
    
    
}

contract FunctionTest1 {
    function externalCall(FuntionTest ft){
        //调用另一个合约的外部函数
        ft.publicFunc();
        ft.externalFunc();
       //ft.internalFunc();调用失败,无法调用internal函数
    }
}


4.pure、view、constant三种函数定义

当函数有返回值时,可以添加这三种定义,用这三种方式定义的函数都只执行读操作,不会进行编译执行。即用了这三种方式定义的函数,不会执行函数里的逻辑,只会执行一个返回的读操作。所以执行这些函数不需要消耗gas费用。

  • pure区别是用于返回非变量,如returns 10;
  • 而view和constant用于返回全局变量,两者的区别为新旧版本
contract HelloWorld4{
    
    uint public a = 1;
    
  //由于被constant声明的函数执行读操作,所以a无法被修改  
  //执行为f(),a依然为1
    function f() constant{
       a = 3;
    }

}

5.函数修饰符

用于以声明方式修改函数的语义,如下例子:

contract HelloWorld{
    
    address public sender;
    
    function HelloWorld(){
        //创建合约时将合约创建者赋值给sender
        sender = msg.sender;
        
    }

  modifier onlyOwner(){
      //如果调用合约的人不是合约创建者则throw
      if(msg.sender != sender) throw;
      _;  //占位符
  }
  
  //这样a函数就只能被合约的创建者调用了
  function a() onlyOwner{
      ...
  }
    
    

6.回退函数

fallback function 回退函数,每一个合约有且仅有一个没有名字的函数,往合约发送消息时,会执行该函数。如果合约要正常接受ether,需要加上payable声明。声明后,当有用户往合约转账时,将触发该函数,可以在里面写相应的逻辑。

7.异常处理

Solidity使用状态恢复来处理异常,就是说当抛出异常时将恢复到调用(包括自调用)前的状态。
抛出异常的方式有assert,require,revert,throw。

  • assert函数,用于条件检查,只能测试内部错误和检查常量。
//检查内部计算是否会整型溢出
function add(uint256 a, uint256 b) internal constant returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }

  • require函数,也是用于条件检查,用于测试调用的输入或者合约状态变量。
function sendHalf(address addr) payable returns (uint balance) {
        require(msg.value % 2 == 0); // 只允许偶数
        .....
    }

  • revert 函数用于标记错误并恢复当前调用。
    function buy(uint amount) payable {
        if (amount > msg.value / 2 ether)
            revert("Not enough Ether provided.");
    }

  • throw 和revert一样,但是throw在0.4.13被弃用,将来会被淘汰。

你可能感兴趣的:(Solidity基础语法)