solidity学习笔记(5)—— Storage(引用传递)和Memory(值传递)

Solidity中有两种类型:值类型和引用类型
Solidity是静态类型的语言,有值类型和引用类型的区别。

如果一个变量是值类型,那么当把它的值传给另一个变量时,是复制值,对新变量的操作不会影响原来的变量;如果该变量是引用类型,那么当它传值给另一个变量时,则是把该值的地址复制给新的变量。这样操作新变量也会导致旧变量的改变。

值类型:
布尔类型(bool)、整型(int)、地址类型(address)、定长字节数组(bytes)、枚举类型(enums)、函数类型(function);

如果一个变量是值类型,给它赋值时永远是值传递!

引用类型:
字符串(string)、数组(array)、结构体(structs)、字典(mapping)、不定长字节数组(bytes)

如果一个变量是引用类型,给它赋值时可以是值,也可以是引用,这决定于该变量是Storage类型还是Memory类型。

关键字:Storage 和 Memory

Storage 是把变量永久储存在区块链中,Memory 则是把变量临时放在内存中,当外部函数对某合约调用完成时,内存型变量即被移除。 你可以把它想象成存储在你电脑的硬盘或是RAM中数据的关系。

大多数时候你都用不到这些关键字,默认情况下 Solidity 会自动处理它们。

状态变量(在函数之外声明的变量)默认为“存储”形式,并永久写入区块链;而在函数内部声明的变量是“内存”型的,它们函数调用结束后消失。

通过指定引用类型变量的关键字,可以人为设置变量为storage或memory。

函数的引用类型参数是storage时,是引用传递;函数的引用类型参数是Memory时,是值传递;函数值类型参数永远是值传递。

contract example {
  uint _a;    // 状态变量_a,值类型变量,不存在memory的定位,就是存在区块链中的
  string _b;  // 状态变量_b,引用类型变量,默认storage
 
  function example1 (string b1){
    _b = b1;  // 参数默认是Memory型变量,进行值传递
  }
    
  function example2 (string storage b2) private/internal {
    _b = b2;  // 参数默认是Memory型变量,进行值传递;但是这里设定为storage,就是进行引用传递了
              // 参数是storage类型时,函数必须是private或internal类型的
  }
    
  function example3 (uint storage/memory a) {
    _a = a;  // error: storage location can only be given for Array or String type
  }  
}

有一个很好的例子:
 

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;
    // 如果你想把副本的改动保存回区块链存储
  }
}

 

你可能感兴趣的:(Solidity)