Solidity / Struct

Struct

struct бол холбоотой өгөгдлийг нэг нэгжид бүлэглэх өгөгдлийн бүтэц. Жишээ нь хэрэглэгчийн нэр, хаяг, үлдэгдлийг тус тусдаа гурван mapping-д хадгалах бус, нэг User struct болгон цэгцэлж болно.

Struct тодорхойлох

solidity
struct StructName {
    Type1 field1;
    Type2 field2;
    Type3 field3;
}
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

contract StudentRegistry {
    struct Student {
        string  name;
        uint256 age;
        uint256 score;
        bool    isActive;
    }
}

Struct үүсгэх

solidity
contract StudentRegistry {
    struct Student {
        string  name;
        uint256 age;
        uint256 score;
        bool    isActive;
    }

    Student public topStudent;

    function setTopStudent() public {
        // Арга 1: field-ийн дарааллаар
        topStudent = Student("Болд", 20, 95, true);

        // Арга 2: нэрлэсэн field (илүү ойлгомжтой)
        topStudent = Student({
            name:     "Болд",
            age:      20,
            score:    95,
            isActive: true
        });
    }

    function getScore() public view returns (uint256) {
        return topStudent.score;   // dot notation-оор хандана
    }
}

Mapping дотор struct

Хамгийн түгээмэл хослол — mapping(address => Struct):

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

contract UserProfile {
    struct Profile {
        string  username;
        uint256 xp;
        uint256 level;
        bool    registered;
    }

    mapping(address => Profile) public profiles;

    function register(string memory _username) public {
        require(!profiles[msg.sender].registered, "Аль хэдийн бүртгэлтэй");
        require(bytes(_username).length > 0, "Нэр хоосон байж болохгүй");

        profiles[msg.sender] = Profile({
            username:   _username,
            xp:         0,
            level:      1,
            registered: true
        });
    }

    function addXP(uint256 amount) public {
        require(profiles[msg.sender].registered, "Эхлээд бүртгүүлэх шаардлагатай");
        profiles[msg.sender].xp += amount;

        // level ахиулах логик
        if (profiles[msg.sender].xp >= profiles[msg.sender].level * 100) {
            profiles[msg.sender].level += 1;
        }
    }

    function getMyProfile() public view returns (Profile memory) {
        return profiles[msg.sender];
    }
}

Array дотор struct

solidity
contract TaskManager {
    struct Task {
        uint256 id;
        string  description;
        address assignedTo;
        bool    completed;
    }

    Task[]   public tasks;
    uint256  private nextId;

    function createTask(string memory desc, address assignee) public {
        tasks.push(Task({
            id:          nextId++,
            description: desc,
            assignedTo:  assignee,
            completed:   false
        }));
    }

    function completeTask(uint256 taskId) public {
        require(taskId < tasks.length, "Буруу ID");
        require(tasks[taskId].assignedTo == msg.sender, "Энэ таны даалгавар биш");
        tasks[taskId].completed = true;
    }

    function getTask(uint256 index) public view returns (Task memory) {
        return tasks[index];
    }

    function getTaskCount() public view returns (uint256) {
        return tasks.length;
    }
}

Function параметрт struct

solidity
contract ProductStore {
    struct Product {
        string  name;
        uint256 price;
        uint256 stock;
    }

    mapping(uint256 => Product) public products;
    uint256 public productCount;

    // struct параметрт авах — memory шаардана
    function addProduct(Product memory newProduct) public {
        products[productCount] = newProduct;
        productCount++;
    }

    // хялбар дуудалт
    function addSimple(string memory name, uint256 price, uint256 qty) public {
        addProduct(Product(name, price, qty));
    }
}

Storage vs Memory struct

Storage pointer — struct-г storage-д шууд засварлана. Gas хямд — sload нэг удаа:

solidity
mapping(address => Profile) public profiles;

function levelUpStorage() public {
    // ✅ storage pointer — шууд storage-д бичнэ
    Profile storage p = profiles[msg.sender];
    p.xp    += 50;
    p.level += 1;
    // нэг SSTORE хийгдэнэ
}

Memory copy — struct-г санах ойд хуулж ажилладаг. Storage-д бичихгүй:

solidity
function levelUpMemory() public {
    // ❌ memory copy — storage-д буцаж бичигдэхгүй!
    Profile memory p = profiles[msg.sender];
    p.xp    += 50;   // зөвхөн memory-д өөрчлөгдөнө
    p.level += 1;
    // profiles[msg.sender] өөрчлөгдсөнгүй!
}

Storage pointer ашиглах нь хэд хэдэн field өөрчлөхөд gas хэмнэнэ:

solidity
// ❌ storage-д 3 удаа бичнэ
profiles[msg.sender].xp     += 50;
profiles[msg.sender].level  += 1;
profiles[msg.sender].active  = true;

// ✅ нэг pointer-ээр 3 field өөрчилнө — gas хямд
Profile storage p = profiles[msg.sender];
p.xp    += 50;
p.level += 1;
p.active = true;

Struct дотор mapping — хориотой

solidity
// ❌ БОЛОМЖГҮЙ — struct дотор mapping байж болохгүй (шууд)
struct BadUser {
    string name;
    mapping(address => bool) friends;   // compile error
}

Ийм хэрэгцээнд тусдаа mapping ашигла:

solidity
// ✅ ЗӨВ
struct User {
    string name;
    uint256 friendCount;
}

mapping(address => User)                        public users;
mapping(address => mapping(address => bool))    public friendships;

Дараагийн хичээлд:

enum — тодорхой утгуудын жагсаалт, state machine загвар ашиглан contract-ийн төлөвийг удирдах аргыг судална.