Harry Liu avatar

【译】智能合约 | Solidity中有哪些实用又简单的存储模式?

ljyxxzj

Published: 28 Nov 2018 › Updated: 28 Nov 2018【译】智能合约 | Solidity中有哪些实用又简单的存储模式?

【译】智能合约 | Solidity中有哪些实用又简单的存储模式?

本文翻译自:contract development - Are there well-solved and simple storage patterns for Solidity? - Ethereum Stack Exchange

在Solidity智能合约开发中,数据结构的定义是非常重要的,下面介绍几种经常用到的数据结构。

Array(元素为Struct)

struct EntityStruct {
    address entityAddress;
    uint entityData;
    // more fields
}

EntityStruct[] public entityStructs;

优点

  • 可以保证按时间顺序排列
  • 可以获得长度
  • 可以通过数组下标随意取值

缺点

  • 不能通过Id随机取值
  • 不能保证唯一性
  • 无法验证重复值
  • 无法控制数组长度

例子:

pragma solidity ^0.4.6;

contract simpleList {

  struct EntityStruct {
    address entityAddress;
    uint entityData;
    // more fields
  }

  EntityStruct[] public entityStructs;

  function newEntity(address entityAddress, uint entityData) public returns(uint rowNumber) {
    EntityStruct memory newEntity;
    newEntity.entityAddress = entityAddress;
    newEntity.entityData    = entityData;
    return entityStructs.push(newEntity)-1;
  }

  function getEntityCount() public constant returns(uint entityCount) {
    return entityStructs.length;
  }
}

Mapping(Id => Struct)

struct EntityStruct {
    uint entityData;
    bool isEntity;
}

mapping (address => EntityStruct) public entityStructs;

优点

  • 可以通过Id取值
  • Id唯一
  • 内部可以包含 arrays, mappings和structs

缺点

  • 无法按照key遍历
  • 无法获得元素的数量
  • 元素的值默认是0,如果要区分当前值为0的时候是否是默认值,需要额外的逻辑检查

例子:

contract mappingWithStruct {

  struct EntityStruct {
    uint entityData;
    bool isEntity;
  }

  mapping (address => EntityStruct) public entityStructs;

  function isEntity(address entityAddress) public constant returns(bool isIndeed) {
    return entityStructs[entityAddress].isEntity;
  }

  function newEntity(address entityAddress, uint entityData) public returns(bool success) {
    if(isEntity(entityAddress)) throw; 
    entityStructs[entityAddress].entityData = entityData;
    entityStructs[entityAddress].isEntity = true;
    return true;
  }

  function deleteEntity(address entityAddress) public returns(bool success) {
    if(!isEntity(entityAddress)) throw;
    entityStructs[entityAddress].isEntity = false;
    return true;
  }

  function updateEntity(address entityAddress, uint entityData) public returns(bool success) {
    if(!isEntity(entityAddress)) throw;
    entityStructs[entityAddress].entityData = entityData;
    return true;
  }
}

Array(元素为Struct) + Mapping(Id => bool)

struct EntityStruct {
    address entityAddress;
    uint entityData;
}

EntityStruct[] public entityStructs;
mapping(address => bool) knownEntity;

优点

  • 可以通过数组下标随意取值
  • Id唯一
  • 内部可以包含 arrays, mappings和structs

缺点

  • 不能通过Id随机取值
  • 无法控制数组长度

例子:

contract arrayWithUniqueIds {

  struct EntityStruct {
    address entityAddress;
    uint entityData;
  }

  EntityStruct[] public entityStructs;
  mapping(address => bool) knownEntity;

  function isEntity(address entityAddress) public constant returns(bool isIndeed) {
    return knownEntity[entityAddress];
  }

  function getEntityCount() public constant returns(uint entityCount) {
    return entityStructs.length;
  }

  function newEntity(address entityAddress, uint entityData) public returns(uint rowNumber) {
    if(isEntity(entityAddress)) throw;
    EntityStruct memory newEntity;
    newEntity.entityAddress = entityAddress;
    newEntity.entityData = entityData;
    knownEntity[entityAddress] = true;
    return entityStructs.push(newEntity) - 1;
  }

  function updateEntity(uint rowNumber, address entityAddress, uint entityData) public returns(bool success) {
    if(!isEntity(entityAddress)) throw;
    if(entityStructs[rowNumber].entityAddress != entityAddress) throw;
    entityStructs[rowNumber].entityData    = entityData;
    return true;
  }
}

Mapping(Id => Struct)+ Array(元素为Id)

struct EntityStruct {
    uint entityData;
    bool isEntity;
}

mapping(address => EntityStruct) public entityStructs;
address[] public entityList;

优点

  • 可以通过Id数组下标随意取值
  • Id唯一
  • 内部可以包含 arrays, mappings和structs
  • 保留了元素声明的顺序
  • 可以获得元素数量
  • 可以通过Id遍历
  • 通过设置布尔值来删除元素

缺点

  • 无法控制数组长度

例子:

contract MappedStructsWithIndex {

  struct EntityStruct {
    uint entityData;
    bool isEntity;
  }

  mapping(address => EntityStruct) public entityStructs;
  address[] public entityList;

  function isEntity(address entityAddress) public constant returns(bool isIndeed) {
      return entityStructs[entityAddress].isEntity;
  }

  function getEntityCount() public constant returns(uint entityCount) {
    return entityList.length;
  }

  function newEntity(address entityAddress, uint entityData) public returns(uint rowNumber) {
    if(isEntity(entityAddress)) throw;
    entityStructs[entityAddress].entityData = entityData;
    entityStructs[entityAddress].isEntity = true;
    return entityList.push(entityAddress) - 1;
  }

  function updateEntity(address entityAddress, uint entityData) public returns(bool success) {
    if(!isEntity(entityAddress)) throw;
    entityStructs[entityAddress].entityData    = entityData;
    return true;
  }
}

Mapping(Id => Struct)+ Array(元素为Id)+ 删除功能

struct EntityStruct {
    uint entityData;
    uint listPointer;
}

mapping(address => EntityStruct) public entityStructs;
address[] public entityList;

优点

  • 可以通过Id数组下标随意取值
  • Id唯一
  • 内部可以包含 arrays, mappings和structs
  • 可以获得元素数量
  • 可以通过Id遍历
  • 通过设置布尔值来删除元素
  • 可以通过删除函数控制剩余元素的数量

缺点

  • 增加了代码复杂度
  • 增加存储成本
  • 元素是无序的

例子:

contract mappedWithUnorderedIndexAndDelete {

  struct EntityStruct {
    uint entityData;
    uint listPointer;
  }

  mapping(address => EntityStruct) public entityStructs;
  address[] public entityList;

  function isEntity(address entityAddress) public constant returns(bool isIndeed) {
    if(entityList.length == 0) return false;
    return (entityList[entityStructs[entityAddress].listPointer] == entityAddress);
  }

  function getEntityCount() public constant returns(uint entityCount) {
    return entityList.length;
  }

  function newEntity(address entityAddress, uint entityData) public returns(bool success) {
    if(isEntity(entityAddress)) throw;
    entityStructs[entityAddress].entityData = entityData;
    entityStructs[entityAddress].listPointer = entityList.push(entityAddress) - 1;
    return true;
  }

  function updateEntity(address entityAddress, uint entityData) public returns(bool success) {
    if(!isEntity(entityAddress)) throw;
    entityStructs[entityAddress].entityData = entityData;
    return true;
  }

  function deleteEntity(address entityAddress) public returns(bool success) {
    if(!isEntity(entityAddress)) throw;
    uint rowToDelete = entityStructs[entityAddress].listPointer;
    address keyToMove   = entityList[entityList.length-1];
    entityList[rowToDelete] = keyToMove;
    entityStructs[keyToMove].listPointer = rowToDelete;
    entityList.length--;
    return true;
  }

}

Leave 【译】智能合约 | Solidity中有哪些实用又简单的存储模式? to:

Written by

Read more #solidity posts


Best Posts From Harry Liu

We have not curated any of ljyxxzj's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.

More Posts From Harry Liu