# Solidity极简入门:4. 引用类型：存储位置 storage, memory, calldata

By [DAO4Resilience](https://paragraph.com/@dao4resilience) · 2022-04-24

---

Solidity中的引用类型
--------------

**引用类型(Reference Type)**：包括数组（`array`），结构体（`struct`）和映射（`mapping`），这类变量占空间大，赋值时候直接传递地址（类似指针）。由于这类变量比较复杂，占用存储空间大，我们在使用时必须要声明数据存储的位置。

数据位置
----

solidity数据存储位置有三类：storage，memory和calldata。不同存储位置的gas成本不同。storage类型的数据存在链上，类似计算机的硬盘，消耗gas多；memory和calldata类型的临时存在内存里，消耗gas少。大致用法：

**1.** `storage`：合约里的状态变量默认都是storage，存储在链上。

**2.** `memory`：函数里的参数和临时变量一般用memory，存储在内存中，不上链。

**3.** `calldata`：和memory类似，存储在内存中，不上链。与memory的不同点在于calldata变量不能修改（immutable），一般用于函数的参数。例子：

        function fCalldata(uint[] calldata _x) public pure returns(uint[] calldata){
            //参数为calldata数组，不能被修改
            // _x[0] = 0 //这样修改会报错
            return(_x);
        }
    

### 不同类型相互赋值时的规则：

在不同存储类型相互赋值时候，有时会产生独立的副本（修改新变量不会影响原变量），有时会产生引用（修改新变量会影响原变量）。规则如下：

1\. `storage`（合约的状态变量）赋值给本地`storage`（函数里的）时候，会创建引用，改变新变量会影响原变量。例子：

        uint[] x = [1,2,3]; // 状态变量：数组 x
    
        function fStorage() public{
            //声明一个storage的变量 xStorage，指向x。修改xCopy也会影响x
            uint[] storage xStorage = x;
            xStorage[0] = 100;
        }
    

2\. `storage`赋值给`memory`，会创建独立的复本，修改其中一个不会影响另一个；反之亦然。例子：

        uint[] x = [1,2,3]; // 状态变量：数组 x
        
        function fMemory() public view{
            //声明一个Memory的变量xMemory，复制x。修改xMemory不会影响x
            uint[] memory xMemory = x;
            xMemory[0] = 100;
        }
    

3\. `memory`赋值给`memory`，会创建引用，改变新变量会影响原变量。

4\. 其他情况，变量赋值给`storage`，会创建独立的复本，修改其中一个不会影响另一个。

总结
--

在第4讲，我们介绍了solidity中的引用类型和数据位置，重点是storage, memory和calldata三个关键字的用法。他们出现的原因是为了节省链上有限的存储空间和降低gasfee消耗。下一讲我们会介绍引用类型中的数组。

---

*Originally published on [DAO4Resilience](https://paragraph.com/@dao4resilience/solidity-4-storage-memory-calldata)*
