BudiBadu Logo
Samplebadu

Solidity by Example: Structs

0.8.x

Organizing complex data with this sample code showing struct definitions for grouping related variables, array of structs for collections, storage vs memory data locations, and direct struct modification through storage pointers.

Code

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

contract TodoList {
    struct Todo {
        string text;
        bool completed;
    }

    // Array of structs
    Todo[] public todos;

    function create(string calldata _text) public {
        // Initialize struct
        todos.push(Todo(_text, false));
        
        // Alternative syntax
        // todos.push(Todo({text: _text, completed: false}));
    }

    function get(uint256 _index) public view returns (string memory text, bool completed) {
        Todo storage todo = todos[_index];
        return (todo.text, todo.completed);
    }

    function toggleCompleted(uint256 _index) public {
        Todo storage todo = todos[_index];
        todo.completed = !todo.completed;
    }
}

Explanation

Structs enable you to define custom data types by grouping together related variables, essential for representing complex entities like user profiles, token orders, or multi-field records. Structs can contain any data type including other structs, arrays, and mappings, though structs containing mappings have restrictions on where they can be used. This composability makes structs powerful building blocks for organizing contract state.

Understanding data locations is critical when working with structs. Using Todo storage todo = todos[_index] creates a reference pointer to the struct in storage, meaning any modifications to todo directly update the blockchain state. In contrast, using memory would create a temporary copy that exists only during function execution, and changes would not persist. The calldata location is read-only and used for external function parameters, offering the cheapest gas costs.

Structs are commonly used inside arrays or mappings to organize contract state efficiently. For example, mapping(address => User) could store user profiles, or Order[] public orders could track a marketplace's order history. When initializing structs, you can use positional syntax Todo(_text, false) or named syntax Todo({text: _text, completed: false}), with the latter being more readable for structs with many fields.

Code Breakdown

5-8
struct Todo defines a custom type grouping text and completion status.
11
Todo[] public todos creates a dynamic array of Todo structs.
15
Todo(_text, false) initializes struct using positional arguments.
27
Todo storage todo creates a storage pointer for direct state modification.