13.struct
struct¶
类似Java的Class对象
结构体可以在合约之外声明并在另一个合约中导入。
案例¶
假设您想在图书馆中跟踪您的书籍,您可能想要跟踪每本书的以下属性
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¶
- 为什么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"类型时显式地标记它们,以便其他人阅读和理解代码时更容易理解。
- 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;
}
}