以太坊智能合约 solidity 的常用的数据结构介绍

Solidity 简介

  • Solidity 是一种静态语言类型,在编译前都要指定每个变量的类型。Solidity 提供了几种基本类型,通过几种基本类型的组合,可以组合成复杂类型。
  • 此外更加官方的文章介绍可以参见:https://solidity.readthedocs.io/en/develop/index.html
  • 下面的实例均可以在 remix-ide 中进行测试 。

数组

  • 数组是可以在编译时固定大小的,
    也可以是动态的。对于存储器数组来说,成员类型可以是任意的(也可以是其他数组,映射或结构)。对于内存数组来说 ,成员类型不能是一个映射;如果是公开可见的函数参数,成员类型是必须是ABI类型的。

  • 固定大小 k 的数组和基本类型 T,可以写成 T[k], 动态数组写成 T[ ] 。
    例如, 有5个基本类型为 uint 的动态数组的数组 可以写成 uint[ ][5],(注:
    和一些其他语言相比,这里申明数组的符号表示次序是反过来的)。

  • 为了访问第三动态数组中的第二个 uint, 必须使用 x[2][1](下标是从零开始的,访问模式和声明模式正好相反, 即x[2]是从右边剔除了一阶)。

  • bytes 和 string 是特殊类型的数组。 bytes 类似于 byte[ ],但它是紧凑排列在 calldata 里的。string 等于 bytes , 但不允许用长度或所以索引访问(现在情况是这样的)。

  • 所以 bytes 应该优先于 byte[ ] ,因为它效率更高。

对数组的增删改查操作

  • 在remix-ide 新建一个 array.sol 文件,内容如下:
pragma solidity ^0.4.17;

/**
 * 数组的增、删、改、查
 * https://mshk.top
 */
contract mshk_top_array {

    //声明一个全局数组变量
    uint[] public intArray;

    /*
     * 构造函数
     * 默认向数组中添加一个2009
     */
    function mshk_top_array() public{
      intArray.push(2009);
    }

    /*
     * @dev 添加一个值到数组
     * @param val uint, 要传入的数值
     */
    function add(uint val) public{
        intArray.push(val);
    }

    /*
     * @dev 获取数组的长度
     * @return len uint,返回数组的长度
     */
    function length() public view returns (uint) {
      return intArray.length;
    }

    /*
     * @dev 更新数组的值
     * @param _index uint, 指定的索引
     * @param _value uint, 要修改的值
     */
    function update(uint _index, uint _value) public{
      intArray[_index] = _value;
    }

    /*
     * @dev 获取指定数组索引的值
     * @param _index uint, 索引值
     * @return _value uint, 返回结果
     */
    function valueByIndex(uint _index) public view returns (uint _value){
      uint result = intArray[_index];
      return result;
    }

    /*
     * @dev 删除指定数组索引的值
     * @param _index uint, 索引值
     */
    function delByIndex(uint _index) public{
      uint len=intArray.length;
      if (_index >= len) return;
      for (uint i = _index; i<len-1; i++){
        intArray[i] = intArray[i+1];
      }
      delete intArray[len-1];
      intArray.length--;
    }
}
  • Array 类型有成员,length 和成员函数 push, 更多可参见 : ``Solidity document

String、bytes、Mapping 的使用

  • string 类型没有 length 属性,而bytes 类型有 length 属性。
  • bytes1, bytes2, bytes3, …, bytes32,如果在 bytes 后面带了数字进行声明时,最多可以保存32个字符。一旦声明以后,那么 length 属性就是你声明的长度。
  • mapping,是由键和值组成的mapping(_KeyType => _ValueType)哈希表,初始化每个存在的 key,对应的 value 的值会初始化为所有的字节都为0。_KeyType 和 _ValueType 可以是任意类型。mapping 只允许静态变量或是内部方法中的存储空间引用类型。一般键为地址, 值为余额 mapping(address => uint)。
  • 具体的可以参见,官方文档。
  • 接下来,我们可以创建一个 mapping.sol 文件,对 string、bytes、mapping 进行测试。
pragma solidity ^0.4.17;

/**
 * 对`string`、`bytes`、`mapping`进行测试
 * https://mshk.top
 */
contract string_bytes_mapping {

  //声明一个变量
  string public str;
  bytes public byt;
  mapping(bytes10 => string) public map;

  /*
   * 初始化
   */
  function init() public{
    str = "abc";
    byt = "abc";
    map["mshk"] = "mshk.top";
    map["idoall"] = "idoall.org";
  }

  /*
   * @dev 获取长度
   * @param uint 返回长度
   */
  function lenght() public view returns(uint){
    return byt.length;
  }

  /*
   * @dev 获取map的指定key的值
   * @param _key bytes10,指定的key,如果key不存在,会返回空字符串
   */
  function getMapByKey(bytes10 _key) public view returns(string){
    return map[_key];
  }
}

Enums 和 Structs 的简单应用

  • Enums 是一个用户可以定义类型的方法,可以使用 uint 转换,默认从0开始递增,但不可以隐性转换,转换失败会抛出异常,声明 Enums 时,里面至少要有一个成员。一般用来模拟合约的状态。
  • 创建一个 enums.sol 文件,对 enums 进行测试。
pragma solidity ^0.4.17;

/**
 * 对`enums`进行测试
 * https://mshk.top
 */
contract mshk_top_enums {

    //定义枚举
    enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }

    //声明变量
    ActionChoices choice;
    ActionChoices constant defaultChoice = ActionChoices.GoStraight;

    function setGoRight() public {
        choice = ActionChoices.GoRight;
    }

    function setGoLeft() public {
        choice = ActionChoices.GoLeft;
    }

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

    function setSitStill() public {
        choice = ActionChoices.SitStill;
    }

    // Since enum types are not part of the ABI, the signature of "getChoice"
    // will automatically be changed to "getChoice() returns (uint8)"
    // for all matters external to Solidity. The integer type used is just
    // large enough to hold all enum values, i.e. if you have more values,
    // `uint16` will be used and so on.
    function getChoice() public view returns (ActionChoices) {
        return choice;
    }

    function getDefaultChoice() public pure returns (uint) {
        return uint(defaultChoice);
    }
}
  • 以上代码,第一次调用getChoice方法时,返回的值为0。调用setGoRight方法,对choice设置一个枚举值ActionChoices.GoRight,再次调用getChoice方法时,返回的值为1.

Structs 结构体

  • Structs 结构体,和其他语言一样,可以定义任意类型的结构。Structs 里面可以定义 Mappings,同样在Mappings 中也可以定义 Structs。虽然结构本身可以作为 mapping 的成员值,但是结构不可以包含它本身类型,避免死循环。
  • 建立一个 struts.sol 文件,并对 structs 进行测试。
pragma solidity ^0.4.17;

/**
 * 对 structs 进行测试
 * https://mshk.top
 */
contract  top_struct {

    // Defines a new type with two fields.
    struct User {
        string name;
        uint age;
    }

    //用户列表
    User[] public users;

    /*
     * @dev 添加方法
     */
    function add(string _name, uint _age) public{
        users.push(
            User({
                name:_name,
                age:_age
            })
        );
    }
}
  • Mapping 类型被定义成如mapping(_KeyType => _ValueType)一样,KeyType 和 ValueType 可以是任何类型,其中 ValueType 甚至也可以是Mapping类型。
pragma solidity ^0.4.17;

/**
 * 使用 struct 和 mapping 编写一个简单的智能合约
 * https://mshk.top
 */
contract mshk_top_struct_mapping {

    mapping (address => uint) public balanceOf;
    address public owner;
    event Sent(address sender, address receiver, uint amount); //定义一个时间

    //获取部署合约的账户地址, 并初始化该地址的余额
    function mshk_top_struct_mapping() public{
        owner = msg.sender;
        balanceOf[owner] = 10000;
    }
    //账户地址交易
    function transfer(address _to, uint amount) public{
        if(balanceOf[msg.sender] < amount) {return;}  //进行判断,防止发送账户的余额不足
        if(balanceOf[_to] + amount < balanceOf[_to]){return;}  //防止自己给自己转账,或递归调用(因为每次调用都有额外的花费)
        balanceOf[_to] += amount;
        balanceOf[msg.sender] -= amount;
        Sent(msg.sender,  _to, amount);   ///调用事件
    }

    //挖矿
    function mint(uint amount) public{
         balanceOf[owner] += amount;
    }

}
  • 以上代码,在Browser-solidity中创建以后,能够看到如下图中的效果:

a8231360db5ff75208fba4da0ccb9e04.png

Ether 单位和 Time 单位

  • Ether 的单位关键字有wei, finney, szabo, ether,换算格式如下:
  • 1 ether = 1 * 10^18 wei;
  • 1 ether = 1 * 10^6 szabo;
  • 1 ehter = 1* 10^3 finney;
  • 建立文件 top_ether.sol
pragma solidity ^0.4.17;

/**
 * 对 比特币 Ether 的几个单位进行测试
 * https://mshk.top
 */
contract mshk_top_ether {

    // 定义全局变量
    uint public balance;

    function mshk_top_ether() public{
        balance = 1 ether;  //1000000000000000000
    }

    function mshk_finney() public{
      balance = 1 finney; //1000000000000000
    }

    function mshk_szabo() public{
      balance = 1 szabo;  //1000000000000
    }

    function mshk_wei() public{
      balance = 1 wei; //1
    }
}
  • Time 的单位关键字有seconds, minutes, hours, days, weeks, years
  • 创建文件 time.sol
pragma solidity ^0.4.17;

/**
 * 对 Time 单位进行测试
 * https://mshk.top
 */
contract mshk_top_time {

    // 定义全局变量
    uint public _time;

    function mshk_top_time() public{
      _time = 100000000;
    }

    function mshk_seconds() public view returns(uint){
      return _time + 1 seconds; //100000001
    }

    function mshk_minutes() public view returns(uint){
      return _time + 1 minutes; //100000060
    }

    function mshk_hours() public view returns(uint){
      return _time + 1 hours; //100003600
    }

    function mshk_weeks() public view returns(uint){
      return _time + 1 weeks; //100604800
    }

    function mshk_years() public view returns(uint){
      return _time + 1 years; //131536000
    }
}

Address

  • address 类型是一个由 20 字节长度的值(以太坊的地址)组成的。地址类型有很多成员变量,是所有合约的基础。常用的两个成员为:

    • .balance,地址的余额(单位为:wei)
    • .transfer,发送以太币(单位为:wei)到一个地址,如果失败会抛出异常,会撤回发送。
    • 创建文件 address.sol
pragma solidity ^0.4.17;

/**
 * 对 Address 的测试
 * https://mshk.top
 */
contract mshk_top_address {

    // 定义全局变量
    address public _a;
    address public _b;

    function mshk_top_address() public{
      _a = msg.sender;  //调用合约用户的地址
      _b = this;  //当前合约的地址
    }

    function geta() public view returns(address){
      return _a;
    }

    function getb() public view returns(address){
      return _b;
    }
}
  • Solidity 编写注意事项一

你可能感兴趣的:(#,Ethereum,区块链从,1.0,到,3.0,的技术分享锦集及讲解)