Solidity中的calldata,storage,memory

Solidity中的calldata,storage,memory,第1张

目录

calldata

memory

storage

三者之间的转换

storage作为参数,赋值到memory

(1)

(2)

(3)

storage作为参数,赋值给storage

memory作为参数,赋值给memory

memory作为参数,赋值给storage


calldata

官方文档对calldata的描述:

Calldata is a non-modifiable, non-persistent area where function arguments are stored, and behaves mostly like memory.

翻译:Calldata是一个不可修改的、非持久化的区域,函数参数存储在这里,其行为主要类似于内存。

它只能用于函数声明参数(而不是函数逻辑)

它是不可变的(不能被覆盖和更改),调用数据避免了数据拷贝,并确保数据不被修改

它必须用于external函数的动态参数

它是临时的(该值在事务完成后会销毁)

它是最便宜的存储位置,一般建议将函数参数声明为calldata,因为gas费会比较低。

是const

外部函数的参数(不包括返回参数)被强制指定为calldata

memory

简介:在合约中的本地内存变量。它的生命周期很短,当函数执行结束后就销毁了

内存是一个字节数组,内存槽为256位(32字节)数据仅在函数执行期间存在,执行完毕后就被销毁,读或写一个内存槽都会消耗3gas为了避免矿工的工作量过大,22个 *** 作之后的单 *** 作成本会上涨 storage

简介:在合约中可以被所有函数访问的全局变量。storage是永久的存储,意味着以太坊会把它保存到公链环境里的每一个节点

存储中的数据是永久存在的。存储是一个key/value库- 存储中的数据写入区块链,因此会修改状态,这也是存储使用成本高的原因。 占用一个256位的存储槽需要消耗20000 gas,修改一个已经使用的存储槽的值,需要消耗5000 gas,当清零一个存储槽时,会返还一定数量的gas,存储按256位的槽位分配,即使没有完全使用一个槽位,也需要支付其开销 三者之间的转换 storage作为参数,赋值到memory (1)
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)
pragma solidity ^0.4.24;

contract Person {

    string public  _name;

    constructor() public {
        _name = "chenqin";
    }

    function f() public view{
        modifyName(_name);
    }

    function modifyName(string name) public pure{
        string memory name1 = name;
        bytes(name1)[0] = 'L';
    }
}
分析 在这里一开始deploy合约时,设置的_name为"chenqin"然后,调用f()函数,将storage类型的状态变量_name作为参数,赋值给函数modifyName函数的memory类型的name,为值传递之后,在modifyName函数中,还将memory类型的name赋值给memory类型的name1,为引用传递!改变一个另一个也跟着改变,最后,因为先是进行了值传递,name与_name之间已经互不影响了,所以不会跟着改变_name。(标记)处的代码并不会修改_name的值因此,不管如何以上函数,_name始终为chenqin (3)
pragma solidity ^0.4.24;

contract Person {

    string public  _name;
    string public changedName;

    constructor() public {
        _name = "chenqin";
    }

    function f() public{//不能声明为view,因为改变了状态变量
        modifyName(_name);
    }

    function modifyName(string name) public{//不能声明为view,因为改变了状态变量
        changedName = name;
        bytes(name)[0] = 'L';
    }
}
分析 调用f()函数,将storage类型的状态变量_name作为参数,赋值给函数modifyName(string) memory类型的name形参,为值传递然后,memory类型的name作为形参,赋值给storage类型的状态变量changedName,为值传递因此,(标记)的那行代码,name的值的改变不会导致changedName的值的改变,更不要说_name了调用f函数,最终的结果是:_name=chenqin,changeName=chenqin storage作为参数,赋值给storage
pragma solidity ^0.4.24;

contract Person {

    string public  _name;

    constructor() public {
        _name = "chenqin";
    }

    function f() public{
        modifyName(_name);
    }

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

PS:如果modifyName函数不声明为internal会报错:这是因为形参是默认为memory类型的,这里声明为storage,那么函数的类型就必须声明为internal或者private

分析 调用f()函数,首先会将为storage类型的_name变量,赋值给modifyName函数storage类型的name,为引用传递然后在modifyName函数中,将storage类型的name变量,赋值给storage类型的name1变量,为引用传递都为引用传递,所以最后name1值的变化会导致_name的值的变化调用f函数前:_name=chenqin。调用f函数后:_name=Lhenqin

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

function modifyName(string storage name) internal {
        bytes(name)[0] = 'L';
    }
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函数,将memory类型的name,赋值给memory类型的name1,为引用传递这时候改变name1的值,它的值也随之改变 memory作为参数,赋值给storage
pragma solidity ^0.4.24;

contract Person {

    string public  _name;

    constructor() public {
        _name = "chenqin";
    }

    function f(string name) public{
        _name = name//(x)
        name = "ikun"(y)
    }

}
分析 调用f函数,将memory类型的name,赋值给storage类型的_name,为值传递(x)处_name的值会被修改成name,然后不再随name的改变而改变,即(y)处代码对_name无影响。f函数执行完的结果还是:_name=chenqin

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/2990908.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-09-23
下一篇 2022-09-23

发表评论

登录后才能评论

评论列表(0条)

保存