跳转至

13.struct

struct

类似Java的Class对象

结构体可以在合约之外声明并在另一个合约中导入。

image-20231007134655746

案例

假设您想在图书馆中跟踪您的书籍,您可能想要跟踪每本书的以下属性

Title Author Subject Book ID

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

contract StructDemo {
    // book struct
    struct Book {
        string title;
        string author;
        uint256 book_id;
    }
    //    创建book对象
    Book book;

    function setBook() public {
        //  book = Book("Learn Java", "TP", 1);
        book = Book({title: "Java", author: "TP", book_id: 2});
    }
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;

contract Structs {
    struct Car {
        string model;
        uint256 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);

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

案例:TODO list

  1. 为什么function create(string calldata _text) external {}

在Solidity中,函数参数可以是"memory"或"calldata"类型。

"memory"类型表示参数值将在函数内部创建并存储在内存中,

而"calldata"类型表示参数值将在函数调用期间从外部传入,并且只能读取而不能修改

在上面的代码中,"create"函数的参数标记为"calldata",因为它需要从外部传入一个字符串作为参数。因为函数不需要修改该参数的值,所以使用"calldata"类型可以避免在函数内部创建和存储该参数的副本,从而节省gas费用。

可以不加calldata吗

在Solidity 0.8.0及以上版本中,如果函数参数是字符串或数组类型,则默认情况下将被视为"calldata"类型。因此,在上面的代码中,如果省略了"calldata"关键字,则Solidity编译器仍将参数视为"calldata"类型,并且代码仍然可以正常工作。

但是,为了使代码更加清晰和易于理解,建议在函数参数是"calldata"类型时显式地标记它们,以便其他人阅读和理解代码时更容易理解。

  1. function updateText(uint _index, string calldata _text)

为什么_index不加calldata?

"uint"类型是"值类型",而不是"引用类型"。这意味着它的值在函数调用期间被复制到函数的栈帧中,并且不会对外部状态产生任何影响。

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

contract ToDoList {
    //创建对象
    struct Todo{
        string text;
        bool completed;
    }
    // 创建数组存储
    Todo[] public todos;

    // 创建todo item
    // 为什么用calldata? --表示参数值将在函数调用期间从外部传入,并且只能读取而不能修改
    function create(string calldata _text) external {
        todos.push(
            Todo({
                text:_text,
                completed:false
            })
        );
    }
    function updateText(uint _index, string calldata _text) external {
        //方法1: 改变对象一个值的话用这个,使用的gas少
        todos[_index].text=_text;
        //方法2:改变对象多个值的话用这个,使用的gas少
        // Todo storage todo=todos[_index];
        // todo.text=_text;
    }
    function get(uint _index) external view returns (string memory,bool) {
        Todo memory todo=todos[_index];
        return (todo.text,todo.completed);
    }
    function toggleCompleted(uint _index) external {
        todos[_index].completed=!todos[_index].completed;
    }
}