引用類型詳解:數組、結構體、映射、字符串

引用類型詳解:數組、結構體、映射、字符串

學習目標

掌握 Solidity 中四種引用類型(數組、結構體、映射、字符串/變長字節數組)的定義和使用方法。

前置知識

已學習值類型(整型、布爾、地址、定長字節數組等)。


數組(Array)

storage 中的數組

Solidity 中數組分為兩種:

  • 靜態數組 T[K]:長度固定,編譯時確定
  • 動態數組 T[]:長度可變,運行時動態增減

關鍵規則:

  • push() / pop() 只能操作 storage 中的動態數組
  • public 數組自動生成的 getter 函數,參數是下標(index)
  • 數組元素可以是任何類型,包括 struct 和 mapping

memory 中的數組

  • 必須用 new 關鍵字初始化,且長度在創建時確定
  • 創建後長度固定,不能使用 push / pop
  • 適用於函數內部的臨時計算

完整示例

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;

contract ArrayType {
    uint8[3] data;     // storage 靜態數組
    uint8[] ddata;     // storage 動態數組

    // 返回靜態數組(拷貝到 memory 返回)
    function testStaticArray() public view returns(uint8[3] memory) {
        return data;
    }

    // 讀取動態數組
    function testReadDynamicArray() public view returns(uint8[] memory) {
        return ddata;
    }

    // 動態數組寫操作
    function testWriteDynamicArray() public {
        ddata.push(12);
        ddata.pop();
        ddata.push(90);
    }

    // 內存中的動態數組
    function testMemoryDynamicArray(uint8 size) public pure returns(uint8[] memory) {
        uint8[] memory mdata = new uint8[](size); // 必須初始化,不能 push/pop
        return mdata;
    }
}

結構體(Struct)

基本概念

結構體用來自定義數據類型,與 contractenum 類似,是一種用戶定義類型。

特點:

  • 可作為狀態變量、局部變量、函數參數和返回值
  • 可放在 mapping 和數組中
  • 成員可以是 mapping 或數組

基礎示例

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;

contract StructType {
    struct Person {
        string name;
        uint8 age;
    }

    Person master;

    function readPerson() public view returns(Person memory) {
        return master;
    }

    function writePerson(Person memory p) public {
        master = p;
    }

    function writePersonName(string memory name) public {
        master.name = name;
    }

    // memory 中的 struct 不需要 new
    function testMemoryStruct() public pure returns(Person memory) {
        Person memory p;
        p.name = "zhangsan";
        p.age = 25;
        return p;
    }

    // storage 局部變量指向成員變量的數據塊
    function testStorageLocalStruct() public view returns(Person memory) {
        Person storage p = master;
        // 修改 p 會直接修改 master!
        return p;
    }
}

進階示例:結構體與數組、映射的組合

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

contract Structs {
    struct Car {
        string model;
        uint year;
        address owner;
    }

    Car public car;
    Car[] public cars;
    mapping(address => Car[]) public carsByOwner;

    function examples() external {
        // 三種初始化方式
        Car memory toyota = Car("Toyota", 1990, msg.sender);
        Car memory lambo = Car({year: 1980, model: "Lamborghini", owner: msg.sender});
        Car memory tesla;
        tesla.model = "Tesla";
        tesla.year = 2010;
        tesla.owner = msg.sender;

        cars.push(toyota);
        cars.push(lambo);
        cars.push(tesla);

        carsByOwner[msg.sender].push(toyota);

        cars.push(Car("Ferrari", 2020, msg.sender));

        // storage 引用可以修改原始數據
        Car storage _car = cars[0];
        _car.year = 1999;

        // 刪除字段(重置為默認值)
        delete _car.owner;
        delete cars[1];
    }
}

注意delete 不會從數組中移除元素,而是將對應位置重置為默認值(零值)。數組長度不變。


映射(Mapping)

聲明語法

mapping(keyType => valueType) visibility variableName;

類型約束

  • keyType:任何基本類型(uintaddressboolbytesstring 等),不能是用戶自定義的複雜類型(struct、mapping、數組)
  • valueType:任何類型,包括 mapping(嵌套映射)

使用限制

  • 只能作為狀態變量storage 局部變量庫函數參數
  • 不能作為 public 函數的參數和返回值
  • public 的 mapping 自動生成 getter 函數(以 key 作為參數)
  • 無法遍歷(由於 storage layout 的設計,key 經過哈希後分散存儲)

示例

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;

contract MappingType {
    mapping(string => uint8) public ages;

    function getAge(string memory name) public view returns(uint8) {
        return ages[name];
    }

    function setAge(string memory name, uint8 age) public {
        ages[name] = age;
    }
}

提示:訪問 mapping 中不存在的 key 不會報錯,而是返回 valueType 的默認值(如 uint 返回 0,address 返回 0x0)。


變長字節數組與字符串

bytes 與 string

bytesstring 都是引用類型(不是值類型),它們的底層存儲結構類似動態數組。

關鍵區別:

  • string 是 UTF-8 編碼的字節數組,不可通過索引訪問單個字符
  • bytes 是原始字節數組,可以通過索引訪問
  • Solidity 沒有內置字符串操作函數(拼接、截取等需要借助庫或轉為 bytes 操作)
  • stringbytes 之間可以互相轉換(不拷貝數據)

使用規則

場景 推薦類型
任意長度的原始數據 bytes
任意長度的字符串(文本) string
固定長度的數據(1~32 字節) bytes1 ~ bytes32(值類型,更省 gas)

示例

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.2 <0.9.0;

contract BytesAndString {
    string name = "BytesAndString";
    bytes name1 = "BytesAndString1";

    function testStringAndBytes() public view returns(string memory) {
        string memory data = "xyz";
        bytes memory data1 = "abc";

        // storage 到 memory 的拷貝
        data = name;
        data1 = name1;

        // 類型轉換
        data1 = bytes(data);
        data = string(data1);

        return data;
    }
}

小結

類型 關鍵特點
數組 storage 可動態增減,memory 定長;push/pop 僅限 storage 動態數組
結構體 自定義復合類型;memory 中無需 new;storage 局部變量是引用
映射 鍵值對存儲;不可遍歷;不能作為函數參數/返回值
string/bytes 引用類型;string 不可索引;固定長度優先用 bytesN 節省 gas

下一篇存儲位置與拷貝機制 —— 理解 storage、memory、calldata 的區別及引用類型的拷貝規則。

主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/7489

(0)
Walker的頭像Walker
上一篇 2026年3月8日 15:11
下一篇 12小時前

相關推薦

  • Web3 概述與願景

    Web3 概述與願景 學習目標 理解 Web1、Web2、Web3 的演進歷程與核心區別 掌握 Web3 的核心理念:去中心化、數據確權、用戶主權 瞭解 Web3 帶來的創新機會與全新商業模式 熟悉 Web3 開發者的學習路線圖 前置知識 基本的互聯網使用經驗 對軟件開發有初步瞭解(非必須,但有助於理解技術部分) 一、Web1 → Web2 → Web3 的…

    Web3與WASM 2026年3月10日
    5800
  • 繼承多態與庫合約

    繼承多態與庫合約 學習目標 掌握 Solidity 繼承機制與多態 理解 C3 線性化算法 掌握庫合約(library)的定義和使用 繼承基礎 繼承定義 使用 is 關鍵字 繼承的實現方式是代碼拷貝:部署後變成一個合約 可見性與繼承 private:子合約不可見,但不能定義同名成員 internal:子合約可見 public:完全可見 event 和 mod…

    Web3與WASM 2026年3月10日
    5200
  • Solidity 入門與開發環境

    Solidity 入門與開發環境 學習目標 理解智能合約的本質與核心特性 掌握合約在以太坊上的運行原理(Transaction + EVM) 認識 Solidity 語言特點與開發工具鏈 編寫並部署第一個智能合約 前置知識 瞭解區塊鏈基本概念(區塊、交易、共識) 瞭解以太坊賬戶模型(EOA 與合約賬戶) 基本編程經驗(任意語言均可) 一、智能合約的根本性質 …

    2026年3月10日
    9800
  • 函數定義與訪問控制

    函數定義與訪問控制 學習目標 掌握 Solidity 函數定義、可見性修飾符、交易屬性、modifier 和構造函數。 函數定義 一般形式 function fname([參數]) [可見性][交易屬性][modifier...] returns(返回值) { ... } 函數簽名:fname([參數]) —— 唯一標識一個函數 返回值:returns(返回…

    Web3與WASM 2026年3月10日
    5000
  • 動態調用與Fallback機制

    動態調用與Fallback機制 學習目標 掌握 call 動態調用的語法與使用場景 理解 calldata 數據結構(selector + 參數編碼) 掌握 fallback / receive 函數的觸發機制 理解 tx、msg、block 三種上下文變量的區別 call 動態調用 基本語法 (bool success, bytes memory data…

    2026年3月10日
    5800
簡體中文 繁體中文 English