美文网首页林梓技术分享集
Solodity知识点集 — Storage与Memory 与接

Solodity知识点集 — Storage与Memory 与接

作者: 童蒙vlog | 来源:发表于2018-04-24 00:15 被阅读14次

    Storage与Memory

    在 Solidity 中,有两个地方可以存储变量 —— storagememory

    Storage 变量是指永久存储在区块链中的变量。 Memory 变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除。

    大多数时候你都用不到这些关键字,默认情况下 Solidity 会自动处理它们。 然而也有一些情况下,你需要手动声明存储类型,主要用于处理函数内的 结构体数组 时:

    contract SandwichFactory {
      struct Sandwich {
        string name;
        string status;
      }
    
      Sandwich[] sandwiches;
    
      function eatSandwich(uint _index) public {
        // Sandwich mySandwich = sandwiches[_index];
    
        // ^ 看上去很直接,不过 Solidity 将会给出警告
        // 告诉你应该明确在这里定义 `storage` 或者 `memory`。
    
        // 所以你应该明确定义 `storage`:
        Sandwich storage mySandwich = sandwiches[_index];
        // ...这样 `mySandwich` 是指向 `sandwiches[_index]`的指针
        // 在存储里,另外...
        mySandwich.status = "Eaten!";
        // ...这将永久把 `sandwiches[_index]` 变为区块链上的存储
    
        // 如果你只想要一个副本,可以使用`memory`:
        Sandwich memory anotherSandwich = sandwiches[_index + 1];
        // ...这样 `anotherSandwich` 就仅仅是一个内存里的副本了
        // 另外
        anotherSandwich.status = "Eaten!";
        // ...将仅仅修改临时变量,对 `sandwiches[_index + 1]` 没有任何影响
        // 不过你可以这样做:
        sandwiches[_index + 1] = anotherSandwich;
        // ...如果你想把副本的改动保存回区块链存储
      }
    }
    

    函数可见性: internal 和 external

    internalprivate 类似,不过, 如果某个合约继承自其父合约,这个合约即可以访问父合约中定义的“内部”函数。

    externalpublic 类似,只不过这些函数只能在合约之外调用 - 它们不能被合约内的其他函数调用。

    contract Sandwich {
      uint private sandwichesEaten = 0;
    
      function eat() internal {
        sandwichesEaten++;
      }
    }
    
    contract BLT is Sandwich {
      uint private baconSandwichesEaten = 0;
    
      function eatWithBacon() public returns (string) {
        baconSandwichesEaten++;
        // 因为eat() 是internal 的,所以我们能在这里调用
        eat();
      }
    }
    

    与其他合约的交互

    如果我们的合约需要和区块链上的其他的合约会话,则需先定义一个 interface (接口)。

    假设在区块链上有这么一个合约:

    contract LuckyNumber {
      mapping(address => uint) numbers;
    
      function setNum(uint _num) public {
        numbers[msg.sender] = _num;
      }
    
      function getNum(address _myAddress) public view returns (uint) {
        return numbers[_myAddress];
      }
    }
    

    现在假设我们有一个外部合约,使用 getNum 函数可读取其中的数据。

    首先,我们定义 LuckyNumber 合约的 interface :

    contract NumberInterface {
      function getNum(address _myAddress) public view returns (uint);
    }
    

    在我们的 app 代码中使用这个接口,合约就知道其他合约的函数是怎样的,应该如何调用,以及可期待什么类型的返回值。

    使用接口

    上面的接口,我们可以在合约中这样使用:

    contract MyContract {
      address NumberInterfaceAddress = 0xab38...;
      // ^ 这是FavoriteNumber合约在以太坊上的地址
      NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);
      // 现在变量 `numberContract` 指向另一个合约对象
    
      function someFunction() public {
        // 现在我们可以调用在那个合约中声明的 `getNum`函数:
        uint num = numberContract.getNum(msg.sender);
        // ...在这儿使用 `num`变量做些什么
      }
    }
    

    通过这种方式,只要将您合约的可见性设置为public(公共)或external(外部),它们就可以与以太坊区块链上的任何其他合约进行交互。

    处理多返回值

    function multipleReturns() internal returns(uint a, uint b, uint c) {
      return (1, 2, 3);
    }
    
    function processMultipleReturns() external {
      uint a;
      uint b;
      uint c;
      // 这样来做批量赋值:
      (a, b, c) = multipleReturns();
    }
    
    // 或者如果我们只想返回其中一个变量:
    function getLastReturnValue() external {
      uint c;
      // 可以对其他字段留空:
      (,,c) = multipleReturns();
    }
    

    if 语句

    function eatBLT(string sandwich) public {
      // 看清楚了,当我们比较字符串的时候,需要比较他们的 keccak256 哈希码
      if (keccak256(sandwich) == keccak256("BLT")) {
        eat();
      }
    }
    

    相关文章

      网友评论

      • IT人故事会:贵在坚持,么么哒!我也是个爱写文章的人

      本文标题:Solodity知识点集 — Storage与Memory 与接

      本文链接:https://www.haomeiwen.com/subject/yzxdlftx.html