Solidity:常用数据结构

2024-05-28 20:39:22 浏览数 (2)

在 Solidity 中,有各种各样的数据结构可用于组织和处理信息。以下是一些最常用的数据结构。

1. Array

在 Solidity 中,数组(Array)是一种基础的数据结构,它能存储同一类型的多个元素,元素在数组里的顺序由其索引值决定。根据所定义的长度,数组可以分为两种类型:定长动态。确定长度的数组在创建时固定其大小,之后就不能再改变;动态数组则没有固定的长度,可以添加或删除元素。

创建数组

静态数组的创建方式如下,其中 <Type> 是元素的数据类型,<Size> 是数组长度:

代码语言:javascript复制
<Type>[<Size>] arrayName;

例如,创建一个长度为5且元素类型为uint的数组,可以如下创建:

代码语言:javascript复制
uint[5] myArray;

对于动态数组,其创建方式如下:

代码语言:javascript复制
<Type>[] arrayName;

例如,创建一个动态数组,元素类型为uint

代码语言:javascript复制
uint[] myArray;

访问和修改数组中元素

在 Solidity 中,使用数组的索引(从0开始)可以访问或修改数组中的元素。例如:

代码语言:javascript复制
myArray[0] = 10;  // 修改数组中第一个元素的值为10
uint firstElement = myArray[0];  // 访问数组中的第一个元素

数组的属性和方法

对于数组,有以下一些常用的属性和方法:

length属性:返回数组的长度。•push方法:只适用于动态数组,用于在数组的末尾添加一个元素,同时数组的长度会增加1。•pop方法:只适用于动态数组,用于删除数组的最后一个元素,同时数组的长度会减少1。

下面的示例中展示了如何在 Solidity 中使用动态数组:

代码语言:javascript复制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

contract Test {
    uint[] public numArray;

    // 添加元素到数组中
    function addToArray(uint num) public {
        numArray.push(num);
    }

    // 获取数组的长度
    function getArrayLength() public view returns (uint) {
        return numArray.length;
    }

    // 根据索引获取数组中的元素
    function getElement(uint index) public view returns (uint) {
        return numArray[index];
    }

    // 移除数组的最后一个元素
    function removeLastElement() public {
        numArray.pop();
    }
}

2. Struct

在Solidity中,结构体(Struct)是一种复杂的数据类型,允许你组合多个不同类型的变量到一个单独的实体。

创建一个结构体的基本语法如下:

代码语言:javascript复制
struct StructName {
    Type1 variable1;
    Type2 variable2;
    ...
}

其中,“StructName”是你为结构体定义的名字,“Type1”和“Type2”是变量的数据类型(例如 uint、address、string等), “variable1”和“variable2”是这些变量的名字。

以下是一个具体的结构体定义示例:

代码语言:javascript复制
struct Student {
    uint id;
    string name;
    uint age;
}

在定义了结构体之后,你可以创建一个新的结构体实例,并初始化其值。例如:

代码语言:javascript复制
Student memory newStudent = Student({
    id: 1,
    name: "Alice",
    age: 20
});

注意,在上面的代码块中,“memory”关键字是必需的,表示这个结构体实例是存在于内存中的。

你还可以直接访问和修改结构体的成员变量。例如:

代码语言:javascript复制
newStudent.name = "Bob";  // 修改结构体实例中的"name"字段
string studentName = newStudent.name;  // 访问结构体实例中的"name"字段

另外,你还可以将结构体存储在数组或者映射中,以实现更复杂的数据管理。例如:

代码语言:javascript复制
// 存储在数组中
Student[] public students;

// 存储在映射中,其中地址是键,Student结构体为值
mapping(address => Student) public studentInfo;

下面的示例展示了 Struct 的简单使用场景:

代码语言:javascript复制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

contract StructExample {
    struct Student {
        uint256 id;
        string name;
        uint256 age;
    }

    Student[] public students;

    function addStudent(
        uint256 _id,
        string calldata _name,
        uint256 _age
    ) public {
        // 3种初始化方式
        // 1. 像调用函数一样,初始化时形参的顺序需与结构体字段顺序一致
        students.push(Student(_id, _name, _age));

        // // 2. key => value形式
        // students.push(Student({id: _id, name: _name, age: _age}));

        // // 3. 使用临时变量
        // Student memory stu;
        // stu.age = _age;
        // stu.id = _id;
        // stu.name = _name;
        // students.push(stu);
    }

    function getStudent(uint256 _index)
        public
        view
        returns (
            uint256,
            string memory,
            uint256
        )
    {
        Student memory stu = students[_index];
        return (stu.id, stu.name, stu.age);
    }
}

3. Mapping

在 Solidity 中,映射(mapping)是一种关联一个类型的值(键)到另一个类型的值(值)的数据结构,它类似于许多编程语言中的哈希表或字典。映射的键的类型可以是任何基本类型,包括字节和整数类型,但不能是映射、动态数组、合约、枚举和结构。映射的值的类型则几乎没有任何限制,甚至可以是另一个映射。

以下是创建一个映射的基本语法:

代码语言:javascript复制
mapping(_KeyType => _ValueType) public mappingName;

在这里,_KeyType是键的数据类型,_ValueType是值的数据类型,并且public关键词使得映射可以被合约以外的程序读取(但无法修改)。

举个例子,以下代码创建了一个名为balances的映射,它将地址映射到uint值:

代码语言:javascript复制
mapping(address => uint) public balances;

在创建了映射之后,可以使用中括号[]来访问或修改映射中的元素,

代码语言:javascript复制
balances[address1] = 100;  // 设置地址address1 的余额为100 
uint balance = balances[address1];  // 获取地址address1 的余额

需要注意的是,映射在默认情况下所有键都存在且对应的值默认为类型的初始值,如对应uint的默认是0,对应bool的默认为false

以下是一个更完整的使用映射管理账户余额的 Solidity 合约示例:

代码语言:javascript复制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;

contract MyContract {
    // 定义一个映射,用来存储每个地址对应的余额
    mapping(address => uint) public balances;

    // 存款
    function deposit(uint amount) public {
        // 增加发送者的余额
        balances[msg.sender]  = amount;
    }

    // 获取余额
    function getBalance() public view returns (uint) {
        return balances[msg.sender];
    }
}

4. Enum

在Solidity中,枚举类型(enum)是由开发者定义的一种特殊类型,它允许你创建一组预定义的值。枚举可以被看作是一种限制了值的类型,这有助于使代码更加清晰易懂,减少错误。

以下是定义一个枚举类型的基本语法:

代码语言:javascript复制
enum EnumName {
    Value1,
    Value2,
    ...
}

在这里,“EnumName”是你为枚举定义的名字,“Value1”和“Value2”等则是枚举中的值。

以下是一个实际的枚举定义示例:

代码语言:javascript复制
enum State {
    Created,
    Locked,
    Inactive
}

在此例中,State 是枚举的名字,而 CreatedLockedInactive 则是该枚举中的值。

一旦定义了一个枚举类型,就可以在合约中创建该类型的变量,并将其设置为该枚举中的值。例如:

代码语言:javascript复制
State public state = State.Created;

在上面的代码段中,有一个公开的 State 类型的状态变量,它的初始值被设置为Created

你还可以在合约的函数中修改或检查这个枚举类型的变量:

代码语言:javascript复制
function makeInactive() public {
    state = State.Inactive;  // 修改枚举变量的值
}

function checkState() public view returns(bool) {
    return state == State.Inactive;  // 检查枚举变量的值
}

声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)[1]进行许可,使用时请注明出处。 Author: mengbin[2] blog: mengbin[3] Github: mengbin92[4] cnblogs: 恋水无意[5] 腾讯云开发者社区:孟斯特[6]

References

[1] 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0): https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh [2] mengbin: mengbin1992@outlook.com [3] mengbin: https://mengbin.top [4] mengbin92: https://mengbin92.github.io/ [5] 恋水无意: https://www.cnblogs.com/lianshuiwuyi/ [6] 孟斯特: https://cloud.tencent.com/developer/user/6649301

0 人点赞