Reference Types Explained: Arrays, Structs, Maps, Strings

Reference Types Explained: Arrays, Structs, Mappings, Strings

Learning Objectives

Master the definition and usage of the four reference types in Solidity: arrays, structs, mappings, and strings/variable-length byte arrays.

Prerequisites

Familiarity with value types (integers, booleans, addresses, fixed-length byte arrays, etc.) is assumed.


Arrays

Arrays in storage

Arrays in Solidity are divided into two types:

  • Static arrays T[K]: Fixed length, determined at compile time
  • Dynamic arrays T[]: Variable length, dynamically increased or decreased at runtime

Key rules:

  • push() / pop() can only operate on dynamic arrays in storage
  • public arrays automatically generate getter functions with the index as a parameter
  • Array elements can be of any type, including structs and mappings

Arrays in memory

  • Must be initialized with the new keyword, and the length must be determined at creation
  • Length is fixed after creation, cannot use push / pop
  • Suitable for temporary calculations within functions

Complete Example

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

contract ArrayType {
    uint8[3] data;     // storage static array
    uint8[] ddata;     // storage dynamic array

    // Returns a static array (copied to memory for return)
    function testStaticArray() public view returns(uint8[3] memory) {
        return data;
    }

    // Reads a dynamic array
    function testReadDynamicArray() public view returns(uint8[] memory) {
        return ddata;
    }

    // Dynamic array write operations
    function testWriteDynamicArray() public {
        ddata.push(12);
        ddata.pop();
        ddata.push(90);
    }

    // Dynamic array in memory
    function testMemoryDynamicArray(uint8 size) public pure returns(uint8[] memory) {
        uint8[] memory mdata = new uint8[](size); // Must be initialized, cannot push/pop
        return mdata;
    }
}

Structs

Basic Concepts

Structs are used to define custom data types, similar to contract and enum, they are user-defined types.

Features:

  • Can be used as state variables, local variables, function parameters, and return values
  • Can be placed within mappings and arrays
  • Members can be mappings or arrays

Basic Example

// 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;
    }

    // Structs in memory do not require 'new'
    function testMemoryStruct() public pure returns(Person memory) {
        Person memory p;
        p.name = "zhangsan";
        p.age = 25;
        return p;
    }

    // storage local variable points to the data block of the member variable
    function testStorageLocalStruct() public view returns(Person memory) {
        Person storage p = master;
        // Modifying p will directly modify master!
        return p;
    }
}

Advanced Example: Combination of Structs with Arrays and Mappings

// 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 {
        // Three initialization methods
        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 reference can modify original data
        Car storage _car = cars[0];
        _car.year = 1999;

        // Delete field (reset to default value)
        delete _car.owner;
        delete cars[1];
    }
}

Note: delete does not remove an element from an array, but rather resets the corresponding position to its default value (zero value). The array length remains unchanged.


Mappings

Declaration Syntax

mapping(keyType => valueType) visibility variableName;

Type Constraints

  • keyType: Any elementary type (uint, address, bool, bytes, string, etc.), cannot be user-defined complex types (structs, mappings, arrays)
  • valueType: Any type, including mappings (nested mappings)

Usage Restrictions

  • Can only be used as state variables, storage local variables, library function parameters
  • Cannot be used as parameters or return values for public functions
  • public mappings automatically generate getter functions (with the key as a parameter)
  • Cannot be iterated (due to the storage layout design, keys are scattered after hashing)

Example

// 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;
    }
}

Tip: Accessing a non-existent key in a mapping will not throw an error; instead, it returns the default value of the valueType (e.g., uint returns 0, address returns 0x0).


Variable-length Byte Arrays and Strings

bytes vs. string

bytes and string are both reference types (not value types), and their underlying storage structure is similar to dynamic arrays.

Key differences:

  • string is a UTF-8 encoded byte array, individual characters cannot be accessed by index
  • bytes is a raw byte array, and can be accessed by index
  • Solidity does not have built-in string manipulation functions (concatenation, substring, etc., require a library or conversion to bytes for operations)
  • string and bytes can be converted to each other (without copying data)

Usage Rules

Scenario Recommended Type
Raw data of arbitrary length bytes
Strings (text) of arbitrary length string
Fixed-length data (1~32 bytes) bytes1 ~ bytes32 (value type, saves more gas)

Example

// 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";

        // Copy from storage to memory
        data = name;
        data1 = name1;

        // Type conversion
        data1 = bytes(data);
        data = string(data1);

        return data;
    }
}

Summary

Type Key Features
Array storage can be dynamically increased/decreased, memory is fixed-length; push/pop only for storage dynamic arrays
Struct Custom composite type; no new needed in memory; storage local variables are references
Mapping Key-value storage; not iterable; cannot be function parameters/return values
string/bytes Reference type; string not indexable; fixed length prefers bytesN to save gas

Next Article: Storage Locations and Copying Mechanism — Understand the differences between storage, memory, calldata, and the copying rules for reference types.

主题测试文章,只做测试使用。发布者:Walker,转转请注明出处:https://walker-learn.xyz/archives/7489

(0)
Walker的头像Walker
上一篇 5 days ago
下一篇 Nov 25, 2025 12:00

Related Posts

EN
简体中文 繁體中文 English