Learning Objectives – after this chapter you will be able to:
  • Define a struct and create struct values in three ways.
  • Store structs in arrays and mappings.
  • Use storage references to update a struct and memory copies to read it.
  • Declare structs at file level and import them into other contracts.
Struct
  • A struct lets you combine several variables of different data types into one new, custom type – a record.
  • Think of a struct as a container: when you move the container, everything inside moves with it. A Student struct, for example, can keep a name, roll number and marks together.
  • Structs make code more organised and are the usual way to represent records such as candidates, bidders, rides or tickets (see the course projects).
  • A struct is a reference type, so in functions it needs a data location (storage or memory).
  • A struct cannot contain a member of its own type directly, but it can contain a dynamic array of its own type or be the value of a mapping.
Syntax
struct <StructName> {
    <data type> member1;
    <data type> member2;
}
Where to Declare a Struct
  • Inside a contract – used by that contract and by contracts that inherit from it (referred to as ContractName.StructName from outside).
  • Outside a contract (file level) – defined in a separate file and brought in with import, so several contracts can share it. The course projects use this style, e.g. CandidateMaster.sol defines struct Candidate, which VotePanelContract imports.
Creating Struct Values
Student memory s1 = Student("Asha", 101, 92);                    // 1. positional
Student memory s2 = Student({name: "Ravi", roll: 102, marks: 85}); // 2. named fields
Student memory s3;                                                 // 3. empty, then set
s3.name = "Meera"; s3.roll = 103; s3.marks = 78;
storage reference vs memory copy
  • Student storage s = students[i]; – a reference; changing s.marks updates the blockchain.
  • Student memory s = students[i]; – a copy; changes are lost after the function ends.
  • delete students[i]; resets every member to its default value.
Example : Structs with Array and Mapping
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

struct Student {               // file-level struct (can be imported by other files)
    string name;
    uint roll;
    uint marks;
}

contract StudentRegistry {
    Student[] public students;                   // struct inside an array
    mapping(uint => Student) public byRoll;      // struct as a mapping value

    function addStudent(string calldata name, uint roll, uint marks) external {
        Student memory s = Student({name: name, roll: roll, marks: marks});
        students.push(s);
        byRoll[roll] = s;
    }

    function updateMarks(uint index, uint newMarks) external {
        Student storage s = students[index];     // reference to stored data
        s.marks = newMarks;                      // updates the blockchain
        byRoll[s.roll].marks = newMarks;
    }

    function tryUpdateCopy(uint index, uint newMarks) external view returns (uint) {
        Student memory s = students[index];      // copy only
        s.marks = newMarks;                      // NOT saved
        return s.marks;
    }

    function getStudent(uint roll) external view returns (Student memory) {
        return byRoll[roll];                     // structs can be returned
    }

    function count() external view returns (uint) {
        return students.length;
    }
}
Key Takeaways
  • A struct groups related fields of different types into one custom type.
  • Create with positional or named arguments; store in arrays and mappings.
  • Use a storage reference to modify stored structs; a memory variable is only a copy.
Download | Print      E-Notes

The PDF E-Notes are the earlier printable version of this chapter. The notes on this page are the latest, revised version.

Question / Answer (15 questions)

Answer : A struct is a user-defined type that groups several variables, possibly of different types, into one record – for example a Student with name, roll number and marks.

Answer : struct StructName { type1 member1; type2 member2; }

Answer : Inside a contract (available to that contract and contracts that inherit from it), or outside a contract at file level, from where it can be imported and shared by multiple contracts.

Answer : Positional arguments: Student("Asha", 101, 92); named arguments: Student({name: "Ravi", roll: 102, marks: 85}); or declare an empty memory struct and assign each member separately.

Answer : A reference type, so when used in a function it must have a data location such as storage or memory.

Answer : A storage variable is a reference to the struct stored on the blockchain, so changes are saved. A memory variable is a temporary copy, so changes are lost after the function ends.

Answer : It loads the struct into memory, which creates a copy; modifying the copy does not affect storage, and the function is declared view, so it cannot change state anyway.

Answer : Declare Student[] students; and use students.push(s), or declare mapping(uint => Student) byRoll; and assign byRoll[roll] = s.

Answer : Not directly, because that would need infinite size. It can, however, contain a dynamic array of its own type or be the value type of a mapping member.

Answer : It resets every member of that struct to its default value (empty string, 0, false …); the array length does not change.

Answer : Yes. With ABI coder v2, which is the default in Solidity 0.8, public and external functions can return structs; they are encoded as tuples.

Answer : With the dot operator, e.g. s.marks or students[0].name.

Answer : For example Candidate in CandidateMaster.sol (Election System), UserRecord in UserRecord.sol (Lottery) and the ItemMaster, BiddersMaster and AuctionRegister structs in BlockMaster.sol (e-Auction).

Answer : It takes an index and returns the struct’s members as separate values (for members of supported types), e.g. students(0) returns name, roll and marks.

Answer : They keep related data together, make code easier to read and maintain, and let contracts model real-world records such as voters, bids, tickets or rides.
MCQ Test : Check Your Understanding (5 questions)

Select an option and press Check Answer, or answer all questions and press Submit Test to see your score. Each answer comes with an explanation.

Q1. A struct is used to:

Show Answer

Correct Answer : B. Group related variables of different types
Structs are custom record types.

Q2. Which statement updates a stored struct permanently?

Show Answer

Correct Answer : B. Student storage s = students[0]; s.marks = 90;
A storage reference modifies the stored data.

Q3. Student({name: "Ravi", roll: 2, marks: 80}) creates a struct using:

Show Answer

Correct Answer : C. Named arguments
Members are given by name.

Q4. Structs declared outside a contract are shared with other files using:

Show Answer

Correct Answer : D. import
File-level structs are imported.

Q5. A struct cannot directly contain:

Show Answer

Correct Answer : D. A member of its own type
A direct self-member would require infinite size.

Bibliography/References

The notes, questions and MCQs on this page are original explanations written for this course. The works listed below were consulted and are cited for attribution and further reading. Product names, logos and trademarks belong to their respective owners. Short quotations, where used, are marked and attributed.

  1. Solidity Team. (n.d.). Types (value types, reference types, mappings, operators, conversions). Solidity Documentation. https://docs.soliditylang.org/en/latest/types.html
  2. Solidity Team. (n.d.). Layout of a Solidity Source File (SPDX, pragmas, imports, comments). Solidity Documentation. https://docs.soliditylang.org/en/latest/layout-of-source-files.html
  3. Solidity Team. (n.d.). Cheatsheet. Solidity Documentation. https://docs.soliditylang.org/en/latest/cheatsheet.html
  4. Modi, R. (2018). Solidity Programming Essentials: A beginner’s guide to build smart contracts for Ethereum and blockchain. Packt Publishing. ISBN 978-1-78883-138-3.