在编写合同时,还应了解引用类型。
与总是传递值的独立副本的值类型不同,引用类型为值提供数据位置。 这三种引用类型为:结构、数组和映射。
数据位置
使用引用类型时,必须显式提供该类型的数据存储位置。 以下选项可用于指定存储类型的数据位置:
memory
:- 存储函数参数的位置
- 生存期限制为外部函数调用的生存期
storage
:- 存储状态变量的位置
- 生存期仅限于合同生存期
calldata
:- 存储函数参数的位置
- 此位置对于外部函数的参数是必需的,但也可用于其他变量
- 生存期限制为外部函数调用的生存期
引用类型总是创建数据的独立副本。
下面举例说明如何使用引用类型:
contract C {
uint[] x;
// the data location of values is memory
function buy(uint[] memory values) public {
x = values; // copies array to storage
uint[] storage y = x; //data location of y is storage
g(x); // calls g, handing over reference to x
h(x); // calls h, and creates a temporary copy in memory
}
function g(uint[] storage) internal pure {}
function h(uint[] memory) public pure {}
}
数组
数组是一种在集合数据结构中存储相似数据的方法。 数组可以是固定大小,也可以是动态大小。 它们的索引从 0 开始。
若要创建固定大小的 k
和元素类型 T
的数组,则需要编写 T[k]
。 对于动态大小数组,应编写 T[]
。
数组元素可以是任何类型。 例如,它们可以包含“uint”、“memory”或“bytes”。 数组还可以包括“映射”或“结构”。
以下示例演示如何创建数组:
uint[] itemIds; // Declare a dynamically sized array called itemIds
uint[3] prices = [1, 2, 3]; // initialize a fixed size array called prices, with prices 1, 2, and 3
uint[] prices = [1, 2, 3]; // same as above
数组成员
以下成员既可以操作数组,又可以获取有关数组的信息:
- length:获取数组的长度。
- push():在数组末尾追加一个元素。
- pop:从数组末尾删除元素。
下面是一些示例:
// Create a dynamic byte array
bytes32[] itemNames;
itemNames.push(bytes32("computer")); // adds "computer" to the array
itemNames.length; // 1
结构
结构是用户可以定义用来表示实际界对象的自定义类型。 结构通常用作架构或用于表示记录。
结构声明示例:
struct Items_Schema {
uint256 _id;
uint256 _price;
string _name;
string _description;
}
映射类型
映射是封装或打包在一起的键值对。 映射最接近 JavaScript 中的字典或对象。 通常使用映射来建模实际对象,并执行快速数据查找。 这些值可以包括结构等复杂类型,这使得映射类型灵活且可读性强。
下面的代码示例使用结构 Items_Schema
,并将 Items_Schema
表示的项列表保存为字典。 映射通过这种方式模拟数据库。
// 定义一个名为 Items 的智能合约
contract Items {
// 定义一个状态变量 item_id,类型为 uint256,用于跟踪下一个项目的 ID。
uint256 item_id = 0;
// 定义一个映射,键为 uint256 类型的项目 ID,值为 Items_Schema 结构体类型的项目。
// 这个映射允许我们通过项目 ID 查找项目数据。
mapping(uint256 => Items_Schema) public items;
// 定义一个结构体 Items_Schema,用于表示项目的属性。
// 注意:Solidity 中结构体成员的定义不需要分号。
struct Items_Schema {
// 定义项目 ID,类型为 uint256。
uint256 _id;
// 定义项目价格,类型为 uint256。
uint256 _price;
// 定义项目名称,类型为 string。
string _name;
}
// 定义一个公共函数 listItem,用于向映射中添加一个新的项目。
// 函数接收项目的价格(_price)和名称(_name)作为参数。
function listItem(uint256 memory _price, string memory _name) public {
// 创建一个新的 Items_Schema 实例,并将其添加到映射 items 中。
// 使用当前的 item_id 作为键。
// 注意:这里使用了结构体的构造器语法,但 Solidity 0.6.0 及更高版本中推荐使用结构体字面量语法。
//items[item_id] = Items_Schema({
//_id: item_id,
//_price: _price,
//_name: _name
//});
items[item_id] = Items_Schema(item_id, _price, _name);
// 增加 item_id 的值,准备为下一个项目分配新的 ID。
item_id += 1;
}
}
备注:
映射签名 uint256 => Items_Schema
表示键是无符号整数类型,值是 Items_Schema
结构类型。