SOL01:Solidity语言基础

2020-04-14  本文已影响0人  杨强AT南京

  Solidity是传说中编写智能合约的脚本语言,运行在EVM中;用以解决区块链中的任务执行。一个目前看起来还非常稚嫩的语言。这里做一个结构性介绍。并据此展开详细的说明。


Solidity语言特点

Slidity语言结构

源代码文件

  1. 源代码文件与其他语言一样,使用文本文件,扩展名使用sol。

  2. 文件的的组织操作系统的文件一样,使用目录组织;

    • 文件之间使用import引用,引用可以指定目录名。这个与ES6语法类似。
    • import "filename";
      • 此语句将从 “filename” 中导入所有的全局符号到当前全局作用域中。
    • import * as symbolName from "filename";
      • 创建一个新的全局符号 symbolName,其成员均来自 "filename" 中全局符号。
    • import {symbol1 as alias, symbol2} from "filename";
      • 创建新的全局符号 alias 和 symbol2,分别从 "filename" 引用 symbol1 和 symbol2 。
    • import "filename" as symbolName;
      • 条语句等同于 import * as symbolName from "filename";。

目录

文件结构

    • 版本申明
    • import
  1. 合约

    • contract 合同名 {}
  2. 注释

    • 与javascript一样,行注释与块注释。
    • //
    • /**/

例子

  1. other.sol
pragma solidity ^0.6.1;

contract Other {
    uint value;
}

  1. solidity.sol
pragma solidity ^0.6.1;

import "./other.sol";
// 行注释
contract MySol is Other {
    /**
    块注释
    */
    uint age;
}

  1. 编译
    • solcjs --abi solidity.sol other.sol
多文件编译

合约contract

合约定义


    contract 合约名 [is] 父合约{
        // 1. 状态变量;
        // 2. 函数;
        // 3. 事件;
        // 4. 结构类型;
        // 5. 枚举类型;
    }

状态变量


    contract MyContract {
        uint varState; // 状态变量
        // ...
    }

函数与函数修饰


contract Purchase {
    address public seller;

    modifier onlySeller() { // 修饰器
        require(
            msg.sender == seller,
            "Only seller can call this."
        );
        _;
    }

    function abort() public onlySeller { // 函数与修饰器使用
        // ...
    }
}

事件

    contract SimpleAuction {
        
        event HighestBidIncreased(address bidder, uint amount); // 事件

        function bid() public payable {
            // ...
            emit HighestBidIncreased(msg.sender, msg.value); // 触发事件
        }
    }

结构类型

    contract Ballot {
        struct Voter { // 结构
            uint weight;
            bool voted;
            address delegate;
            uint vote;
        }
        // .....
    }

枚举类型

    contract Purchase {
        enum State { Created, Locked, Inactive } // 枚举
    }

合同继承

    pragma solidity ^0.4.16;

    contract owned {
        function owned() { owner = msg.sender; }
        address owner;
    }

    // 使用 is 从另一个合约派生。派生合约可以访问所有非私有成员,包括内部函数和状态变量,
    // 但无法通过 this 来外部访问。
    contract mortal is owned {
        function kill() {
            if (msg.sender == owner) selfdestruct(owner);
        }
    }

抽象合约

    contract Feline {    // 可以包含实现的就是抽象合约,这里只有一个抽象函数,实际也是接口合约。
        function utterance() public returns (bytes32);   
    }
    contract Cat is Feline {
        function utterance() public returns (bytes32) { return "miaow"; }
    }

pragma solidity ^0.4.16;

library Set {
  // 我们定义了一个新的结构体数据类型,用于在调用合约中保存数据。
  struct Data { mapping(uint => bool) flags; }

  // 注意第一个参数是“storage reference”类型,因此在调用中参数传递的只是它的存储地址而不是内容。
  // 这是库函数的一个特性。如果该函数可以被视为对象的方法,则习惯称第一个参数为 `self` 。
  function insert(Data storage self, uint value)
      public
      returns (bool)
  {
      if (self.flags[value])
          return false; // 已经存在
      self.flags[value] = true;
      return true;
  }

  function remove(Data storage self, uint value)
      public
      returns (bool)
  {
      if (!self.flags[value])
          return false; // 不存在
      self.flags[value] = false;
      return true;
  }

  function contains(Data storage self, uint value)
      public
      view
      returns (bool)
  {
      return self.flags[value];
  }
}

contract C {
    Set.Data knownValues;

    function register(uint value) public {
        // 不需要库的特定实例就可以调用库函数,
        // 因为当前合约就是“instance”。
        require(Set.insert(knownValues, value));
    }
    // 如果我们愿意,我们也可以在这个合约中直接访问 knownValues.flags。
}

数据类型与数据

数据的定义

数据类型与字面值

布尔类型与布尔值

  1. 类型关键字:bool
  2. 布尔值:truefalse

整数类型与整数值

  1. 类型关键值:
    • int / uint (有符号与无符号)
    • 整数也分字节大小:单位是位,8位一个字节,根据对齐规则,必须是8的倍数。
      • int8/uint8
      • 。。。
      • int256/uint256 = int/uint
  2. 整数值:
    • 只支持10与16进制
      • 普通法表示:122
        • 不能前缀0。
        • 16进制使用hex前缀转换:hex"001122FF" 或者 0x前缀。
      • 科学记数法表示:1e10
        • 指数必须是整数,不支持小数。

小数类型与小数值

  1. 小数类型关键字:fixed / ufixed

    • 有符号与无符号小数
    • 小数还可以自带精度表示:
      • ufixedMxN / fixedMxN (M表示表示该类型占用的位数,N表示可用的小数位数)
        • M也必须是8的倍数,最大256。
  2. 小数值:

    • 使用小数点表示小数。 与整数一样,分成普通表示与科学表示。
  3. 例子:

    • ufixed32x2 score = 12.45;
  4. 注意:

    • Solidity 还没有完全支持定长浮点型。可以声明定长浮点型的变量,但不能给它们赋值或把它们赋值给其他变量。。

地址类型与地址值

  1. 地址类型关键字:address
  2. 地址值表示:0x开头的16进制表示。
  3. 地址变量包含多个成员(成员属性与成员函数),用来访问地址相关信息:
    • balance :balance 属性来查询一个地址的余额
    • send/transfer :transfer 函数向一个地址发送 以太币Ether (以 wei 为单位):

数组类型与值表示

  1. 数组关键字:类型[]
  2. 数组的创建:new
  3. 例子:

    pragma solidity ^0.4.16;

    contract C {
        function f(uint len) public pure {
            uint[] memory a = new uint[](7);
            a[6] = 8;
        }
    }
  1. 两个特殊的数组:
    • bytes 与 string 等加以 int8[]或者 byte[]
  2. 例子:
    pragma solidity ^0.4.16;

    contract C {
        function f(uint len) public pure {
            uint[]  a = new uint[](7);
            bytes  b = new bytes(len);   // string b= new string(len)
            // 这里我们有 a.length == 7 以及 b.length == len
            a[6] = 8;
        }
    }
  1. 数组字面值

    • [1, 2, 3, 4]
  2. 数组变量赋值的注意事项:长度一致

    • 下面例子无法赋值:
// 这段代码并不能编译。

pragma solidity ^0.4.0;

contract C {
    function f() public {
        // 这一行引发了一个类型错误,因为 unint[3] memory
        // 不能转换成 uint[] memory。
        uint[] x = [uint(1), 3, 4];
    }
}
  1. 数组的成员

    • length属性:获取数组长度,还可以通过这个成员属性修改数组的长度(只对存储有效,为位置在内存的变量无效,参考后面存储位置的说明)
    • push函数:用来向数组末尾添加数据
    • 这length对字符串数组无效。
  2. 多维数组:

    • bool[2][3] m_pairsOfFlags;

字符串类型与值表示

  1. 字符串也是数组,其字面值表示:

    • "foo":3字节字符数组。
    • 字符串数组与bytes数组可以隐式转换。
  2. 字符串支持转移字符

    • 字符串字面常数支持转义字符,例如 \n,\xNN 和 \uNNNN\xNN 表示一个 16 进制值,最终转换成合适的字节, 而 \uNNNN 表示 Unicode 编码值,最终会转换为 UTF-8 的序列。

枚举类型

  1. 定义枚举类型

    • enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
  2. 使用枚举类型

    • ActionChoices defaultChoice = ActionChoices.GoStraight;
pragma solidity ^0.4.16;

contract test {
    enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
    ActionChoices choice;
    ActionChoices constant defaultChoice = ActionChoices.GoStraight;

    function setGoStraight() public {
        choice = ActionChoices.GoStraight;
    }

结构体


    struct Funder {
        address addr;
        uint amount;
    }


存储位置

pragma solidity ^0.4.0;

contract C {
    uint[] x; // x 的数据存储位置是 storage

    // memoryArray 的数据存储位置是 memory
    function f(uint[] memoryArray) public {
        x = memoryArray; // 将整个数组拷贝到 storage 中,可行
        var y = x;  // 分配一个指针(其中 y 的数据存储位置是 storage),可行
        y[7]; // 返回第 8 个元素,可行
        y.length = 2; // 通过 y 修改 x,可行
        delete x; // 清除数组,同时修改 y,可行
        // 下面的就不可行了;需要在 storage 中创建新的未命名的临时数组, /
        // 但 storage 是“静态”分配的:
        // y = memoryArray;
        // 下面这一行也不可行,因为这会“重置”指针,
        // 但并没有可以让它指向的合适的存储位置。
        // delete y;

        g(x); // 调用 g 函数,同时移交对 x 的引用
        h(x); // 调用 h 函数,同时在 memory 中创建一个独立的临时拷贝
    }

    function g(uint[] storage storageArray) internal {}
    function h(uint[] memoryArray) public {}
}

映射(key - value)

类型转换

运算符与表达式

布尔运算

  1. ! (逻辑非)
  2. && (逻辑与, "and" )
  3. || (逻辑或, "or" )
  4. == (等于)
  5. != (不等于)

整数运算

  1. 比较运算符:
    • <= , < , == , != , >= , > (返回布尔值)
  2. 位运算符:
    • & , | , ^ (异或), ~ (位取反)
  3. 算数运算符:
    • + , - , 一元运算 - , 一元运算 + , * , / , % (取余) , ** (幂), << (左移位) , >> (右移位)

小数运算

  1. 比较运算符:
    • <=, <, ==, !=, >=, > (返回值是布尔型)
  2. 算术运算符:
    • +, -, 一元运算 -, 一元运算 +, *, /, % (取余数)

地址运算

数组运算

  1. 比较运算符:
    • <=, <, ==, !=, >=, > (返回布尔型)
  2. 位运算符:
    • &, |, ^ (按位异或), ~ (按位取反), << (左移位), >> (右移位)
  3. 索引访问:
    • 如果 x 是 bytesI 类型,那么 x[k] (其中 0 <= k < I)返回第 k 个字节(只读)。
  4. .length
    • 表示这个字节数组的长度(对定长只读).

流程控制

  1. JavaScript 中的大部分控制结构在 Solidity 中都是可用的,除了 switch 和 goto。

    • if,else,
    • while,
    • do,
    • for,
    • break,continue,return,
    • ? :
  2. 注意:

    • 用于表示条件的括号不可以被省略,单语句体两边的花括号可以被省略。
    • 与C和JavaScript不同, Solidity 中非布尔类型数值不能转换为布尔类型,因此 if (1) { ... } 的写法在 Solidity 中 无效 。
上一篇下一篇

猜你喜欢

热点阅读