solidity|solidity 基本语法 - 引用类型
引用类型
引用类型和值类型相对,在传递时,并不拷贝一份新的数据,而是传递是指向同一份数据的引用。下面看一个例子:
pragma solidity ^0.4.23;
contract RefTypeTest {
event PrintValue(uint value1, uint value2);
function testRefType() public {
uint[] x;
x.push(1);
x.push(2);
x.push(3);
uint[] y = x;
emit PrintValue( x[0],y[0]);
y[0] = 0;
emit PrintValue( x[0],y[0]);
}
}
上述代码输出的结果为:
[
{
"event": "PrintValue",
"args": {
"0": "1",
"1": "1",
"value1": "1",
"value2": "1",
"length": 2
}
},
{
"event": "PrintValue",
"args": {
"0": "0",
"1": "0",
"value1": "0",
"value2": "0",
"length": 2
}
}
]
从结果中可以看出,x 和y 指向了同一份数据。solidity中的引用类型包括,动态数组和结构体两种。
存储位置 solidity中对于复杂的类型(array,struct)有一个额外的概念用于定义变量(成员)的存储位置。solidity 中存储位置分别有memory,storage和calldata. storage是持久化的存储,memory和calldata类似是非持久化的存储。
对于不同的类型变量,都拥有一个默认的存储位置,可以通过memory或是storage关键字改变。对于某些类型的变量,solidity会使用一个强制的存储位置,具体的规则如下:
复杂类型 动态数组(Arrays)
- Forced data location:
- parameters (not return) of external functions: calldata
- state variables: storage
- Default data location:
- parameters (also return) of functions: memory
- all other local variables: storage
动态数组是指在运行期间确定元素个数的为主,solidity中的格式为:
T[] array;
动态数组有两个成员:
- push 向数组追加元素
- length 获得数组中元素的个数
byte[] storageArray;
function pushToArray(byte value) public {
storageArray.push(value);
byte[] memory memoryArray = new byte[](15);
// memoryArray.push(value);
compile error
}
bytes 和 string是两种特殊的数组,bytes 和 byte[]类似,string 是特殊的bytes类型,但是无法访问push 和length元素。
结构体(struct)
struct 是solidity中用于定义新的数据结构的方法,其语法和c语言中的结构体类似。
struct Operation {
bytes31 hash;
uint8 status;
}Operation[] operations;
function addOperation(bytes31 opHash,uint8 status) public {
Operation memory op;
op.hash = opHash;
op.status = status;
operations.push(op);
}
存储位置对复杂类型的影响 复杂类型存储在不同位置的变量,相互赋值的行为会有差异,下面通过一个例子来介绍:
pragma solidity ^0.4.23;
contract Contract{
uint[] x;
// the data location is storage
uint[] y;
// the data location is storageevent PrintUint(uint value1, uint value2);
// Test memory assigin to storage
function m2s(uint[] memoryArray) public {
x = memoryArray;
// works, copies the whole array to storage
x[0] = 1;
emit PrintUint(x[0], memoryArray[0]);
}// Test assigin storage to storage
function s2s() public {
x[0] = 0;
y = x;
y[0] = 1;
emit PrintUint(x[0], y[0]);
}// Test assigin storage to memory
function s2m() public {
y[0] = 0;
uint[] memory memoryArray = y;
memoryArray[0] = 1;
emit PrintUint(memoryArray[0], y[0]);
}// Test memoryArray assigin to memoryArray
function m2m(uint[] memoryArray) public {
// default local variable is in storage
// uint[] memoryArray1 = memoryArray;
uint[] memory memoryArray1 = memoryArray;
memoryArray1[0] = 1;
emit PrintUint(memoryArray[0], memoryArray1[0]);
}
}
分别测试上述四个函数,结果如下:
- m2s
[
{
"event": "PrintUint",
"args": {
"0": "1",
"1": "0",
"value1": "1",
"value2": "0",
"length": 2
}
}
]
- m2m
输入 [0]
输出:
[
{
"event": "PrintUint",
"args": {
"0": "1",
"1": "1",
"value1": "1",
"value2": "1",
"length": 2
}
}
]
- s2m
[
{
"event": "PrintUint",
"args": {
"0": "1",
"1": "0",
"value1": "1",
"value2": "0",
"length": 2
}
}
]
- s2s
[
{
"event": "PrintUint",
"args": {
"0": "0",
"1": "1",
"value1": "0",
"value2": "1",
"length": 2
}
}
]
从上面的输出结果可以看出,对于存储在不同位置的复杂类型,赋值操作的表现会有所不同,总结如下:
- 【solidity|solidity 基本语法 - 引用类型】storage to storage 拷贝数据, 表现为值类型
- storage to memory 拷贝数据,表现为值类型
- memory to storage 拷贝数据,表现为值类型
- memory to memory 拷贝引用,表现为引用类型
推荐阅读
- 做一件事情的基本原理是什么()
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。
- 六步搭建ES6语法环境
- dubbo基本认识
- HTML基础--基本概念--跟着李南江学编程
- 7、前端--jQuery简介、基本选择器、基本筛选器、属性选择器、表单选择器、筛选器方法、节点操作、绑定事件
- 一般模型化关系——从模型是什么到如何起作用的基本答案
- canvas(一)基本用法
- 带你了解类型系统以及flow和typescript的基本使用
- MySQL数据库的基本操作