有三种类型,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.;

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)[] = '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.;

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)[] = '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.;

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)[] = '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)[] = 'L';
}

4.memory = memory

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

pragma solidity ^0.4.;

contract Person {

    function modifyName(string name) public pure returns(string){

        string memory name1 = name;
bytes(name1)[] = 'L';
return name;
}
}

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

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

solidity数据位置-memory,storage和calldata的更多相关文章

  1. MEMORY Storage Engine MEMORY Tables TEMPORARY TABLE max_heap_table_size

    http://dev.mysql.com/doc/refman/5.7/en/create-table.html You can use the TEMPORARY keyword when crea ...

  2. mysql --The MEMORY Storage Engine--官方文档

    原文地址:http://dev.mysql.com/doc/refman/5.7/en/memory-storage-engine.html The MEMORY storage engine (fo ...

  3. Linux Centos 迁移Mysql 数据位置

    Linux Centos 迁移Mysql 数据位置 由于业务量增加导致安装在系统盘(20G)磁盘空间被占满了, 现在进行数据库的迁移. Mysql 是通过 yum 安装的. Centos6.5Mysq ...

  4. Chrome程序及数据位置变更到非系统盘

    Chrome浏览器在Windows系统上安装过程,没有设置安装位置的步骤,所以默认是安装在C盘的.并且,若Chrome作为主要浏览器使用,随着时间的积累,数据文件会非常多.增加系统盘的负荷. Wind ...

  5. You can add an index on a column that can have NULL values if you are using the MyISAM, InnoDB, or MEMORY storage engine.

    w https://dev.mysql.com/doc/refman/5.7/en/create-index.html MySQL :: MySQL 5.7 Reference Manual :: B ...

  6. solidity中的memory和 storage详解

    Solidity是一种智能合约高级语言,运行在Ethereum虚拟机(EVM)之上.这里我会讲解一下关键字storage和memory的区别. storage的结构是在合约部署创建时,根据你的合约中状 ...

  7. Excel调换数据位置

    选择需要调换位置的项,按住Shift键,拖动数据,移动到BC列中间线处,出现C4:C5时,放开键盘鼠标即可: 若是不按住Shift键,则数据移动到C列:

  8. java例题_36 移动数组中数据位置(用到数组的合并操作)

    1 /*36 [程序 36 移动位置] 2 题目:有 n 个整数,使其前面各数顺序向后移 m 个位置,最后 m 个数变成最前面的 m 个数,比如输入数字 3 为 1 2 3 4 5 6 7 8 9 0 ...

  9. Merkle 树——空间换时间,分而治之的hash表,通过根节点是由它的两个子节点内容的哈希值组成来校验数据完整性,定位篡改的数据位置

    Merkle 树 图 1.5.6.1 - Merkle 树示例 默克尔树(又叫哈希树)是一种二叉树,由一个根节点.一组中间节点和一组叶节点组成.最下面的叶节点包含存储数据或其哈希值,每个中间节点是它的 ...

随机推荐

  1. 无法打开锁文件 /var/lib/dpkg/lock - open (13: 权限不够)

    比如输入apt-get install eclipse,或者apt-get update 会提示 无法打开锁文件 /var/lib/dpkg/lock - open (13: 权限不够)  无法对状态 ...

  2. Visual Studio日文乱码解决方法

    ---恢复内容开始--- 验证N多网上方法之后,没能解决,最后在控制面板->时钟.语言和区域->语言中左下角点击位置,进入区域窗口,管理选项中的更改系统区域语言,设为日语,解决,截图附上. ...

  3. 关于 IdentityServer 部署到生产环境相关问题踩坑记录

    Idsr 定义了几种模式适用于不同的场景: // // 摘要: // OpenID Connect flows. public enum Flows { // // 摘要: // authorizat ...

  4. 【Java】模拟Sping,实现其IOC和AOP核心(一)

    在这里我要实现的是Spring的IOC和AOP的核心,而且有关IOC的实现,注解+XML能混合使用! 参考资料: IOC:控制反转(Inversion of Control,缩写为IoC),是面向对象 ...

  5. java中自己常犯的错误汇总

    package debug; /** 1.定义一个公共的动物类,包含名字.年龄.颜色和吃饭东西方法 2.定义一个猫类,继承动物类,同时拥有玩游戏的本领 3.定义一个狗类,继承动物类,同时拥有看门的本领 ...

  6. canvas-star6-drawMoon.html

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. 洛谷P3600 随机数生成器(期望dp 组合数)

    题意 题目链接 Sol 一条重要的性质:如果某个区间覆盖了另一个区间,那么该区间是没有用的(不会对最大值做出贡献) 首先不难想到枚举最终的答案\(x\).这时我们需要计算的是最大值恰好为\(x\)的概 ...

  8. Linux常用系统命令

    致歉:各位看到此博客的朋友们 因为命令的数量挺多的很多命令也都很简单  我就总结了一下具体的命令和这个命令是做什么的,主要的使用方法是链接到http://man.linuxde.net/的网站的,请各 ...

  9. loadrunner 脚本开发-参数化之将内容保存为参数、参数数组及参数值获取Part 2

    脚本开发-参数化之将内容保存为参数.参数数组及参数值获取 by:授客 QQ:1033553122 ----------------接 Part 1--------------- 把内容保存到参数数组 ...

  10. Android系统启动流程(二)解析Zygote进程启动过程

    1.Zygote简介 在Android系统中,DVM(Dalvik虚拟机).应用程序进程以及运行系统的关键服务的SystemServer进程都是由Zygote进程来创建的,我们也将它称为孵化器.它通过 ...