zoukankan      html  css  js  c++  java
  • solidity数据位置-memory,storage和calldata

     有三种类型,memory,storage和calldata,一般只有外部函数的参数(不包括返回参数)被强制指定为calldata。这种数据位置是只读的,不会持久化到区块链

    storage存储或memory内存
    memory存储位置同我们普通程序的内存类似,即分配,即使用,动态分配,越过作用域即不可被访问,等待被回收。
    而对于storage的变量,数据将永远存在于区块链上。

    总结¶
    强制指定的数据位置:
        •    外部函数的参数(不包括返回参数): calldata,效果跟 memory 差不多
        •    状态变量: storage
    默认数据位置:
        •    函数参数(包括返回参数): memory
        •    所有其它局部变量: storage

     下面举例说明赋值行为:

    1.memory = storage (值传递,互不影响)

    pragma solidity ^0.4.24;

    contract Person {

        int public _age;

        constructor (int age) public {
          _age = age;
        }

        function f() public view{
          modifyAge(_age);
        }

        function modifyAge(int age) public pure{
          age = 100;
        }
    }

    在这里一开始deploy合约时,传入的age值为30,此时_age的值为30

    然后运行f()函数,在这里使用了为storage类型的_age作为函数modifyAge的参数,相当于创建了一个临时变量age(memory类型),将storage类型的变量_age赋值给memory类型的变量age,是值传递,所以在modifyAge函数中,age变量的值的变化并不会影响到_age变量的值

    所以再查看_age的值,还是为30

     2.storage = memory

    当storage是状态变量(即全局变量时),为值传递

    当storage为局部变量时,该赋值会出错,解决方法是将storage的局部变量声明为memory即可

    1)当storage为局部变量时:

    如下面的例子:

    pragma solidity ^0.4.24;
    
    contract Person {
    
        string public  _name;
    
        constructor() public {
            _name = "liyuechun";
        }
    
        function f() public view{
    
            modifyName(_name);
        }
    
        function modifyName(string name) public pure{
    
            string memory name1 = name;
            bytes(name1)[0] = 'L';
        }
    }

    调用f()函数,将storage类型的状态变量_name作为参数赋值给函数modifyName(string) memory类型的name形参,为memory = storage,为值传递

    然后在函数modifyName(string)中,还将memory类型的name形参赋值给memory类型的name1局部变量,memory = memory,为引用传递,改变一个另一个也跟着改变,但是因为先是进行了值传递,name与_name之间已经互不影响了,所以不会跟着改变_name

    2)当storage为状态变量时:

    pragma solidity ^0.4.24;
    
    contract Person {
    
        string public  _name;
        string public changedName;
    
        constructor() public {
            _name = "liyuechun";
        }
    
        function f() public{//不能在声明为view
    
            modifyName(_name);
        }
    
        function modifyName(string name) public{//不能在声明为view
    
            changedName = name;
            bytes(name)[0] = 'L';
        }
    }
    warning:function declared as view,but this expression(potentially) modifies the state and thus requires non-payable(the default) or payable.

    因为函数modifyName(string)改变了值changedName的状态,所以不能声明为view了

    调用f()函数,将storage类型的状态变量_name作为参数赋值给函数modifyName(string) memory类型的name形参,为memory = storage,为值传递

    然后memory类型的name形参赋值给storage类型的状态变量changedName,storage = memory,为值传递,因此name的值的改变不会导致changedName的值的改变,更不要说_name了

    调用f()后为:

    3.storage = storage

    是引用传递,所以一个值的变化一定会导致另一个值的变化

    pragma solidity ^0.4.24;
    
    contract Person {
    
        string public  _name;
    
        constructor() public {
            _name = "liyuechun";
        }
    
        function f() public{
    
            modifyName(_name);
        }
    
        function modifyName(string storage name) internal {
    
            string storage name1 = name;
            bytes(name1)[0] = 'L';
        }
    }

    ⚠️:如果modifyName(string)函数不声明为internal会报错:

    TypeError:Location has to be memory for publicly visible functions(remove the "storage" keyword)

    这是因为形参是默认为memory类型的,这里声明为storage,那么函数的类型就必须声明为internal或者private

    调用f()函数,首先会将为storage类型的_name变量赋值给modifyName(string)函数storage类型的name形参,storage = storage,为引用传递

    然后在modifyName(string)函数中,将storage类型的name变量赋值给storage类型的name1变量,storage = storage,为引用传递

    都为引用传递,所以最后name1值的变化会导致_name的值的变化

    调用f()后:

    其实在这里如果将modifyName(string)函数改成如下,也是能够成功的,因为其实没必要进行两次引用传递:

        function modifyName(string storage name) internal {
    
            bytes(name)[0] = 'L';
        }

    4.memory = memory

    是引用传递,所以一个值的变化一定会导致另一个值的变化

    pragma solidity ^0.4.24;
    
    contract Person {
    
        function modifyName(string name) public pure returns(string){
    
            string memory name1 = name;
            bytes(name1)[0] = 'L';
            return name;
        }
    }

    这里调用modifyName(string)函数,将memory类型的形参赋值给memory类型的局部变量name1,memory = memory,为引用传递

    这时候改变name1的值,从return 的name可以看到,它的值也随之改变

  • 相关阅读:
    re
    jieba
    Normalization的作用,LN,BN,WN
    RBF神经网络
    其他论文
    numpy, pandas,collections.Counter
    tensorflow 相关
    机器翻译(machine translation)相关
    2020 weblogin rce CVE-2020-14882 漏洞利用POC
    CVE-2021-3019 漏洞细节纰漏
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/9587937.html
Copyright © 2011-2022 走看看