文档: https://solidity-by-example.org/
视频教程: https://www.youtube.com/watch?v=xv9OmztShIw&list=PLO5VPQH6OWdVQwpQfw9rZ67O6Pjfo6q-p
说明:
本文内容: Enum
, struct
, data location
, function
, View and Pure Function
, Error
Enum(枚举)
Solidity支持枚举,这对model choice
和keep track of stack
很有用。
枚举可以在contract之外声明。
跟其它编程语言类似, 枚举类默认都可以用数字替代, Solidity
默认是用的uint8
.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
enum Status { Single, Married }
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import "./EnumDeclaration.sol";
contract Enum {
// 对应了0, 1, 2, 3
enum Season { Spring, Summer, Autumn, Winter }
Season public season;
Status public status;
function get() public view returns (Season){
return season;
}
function set(Season s) public {
season = s;
}
function updateToWinter() public {
season = Season.Winter;
}
function deleteToDefault() public {
delete season; // 恢复成默认值: Spring, 也可以说是0
}
function getStatus() public view returns (Status){
return status;
}
function setStatus(Status _status) public {
status = _status;
}
}
struct
这位更是重量级, 终于能自定义类型了.
可以通过创建struct
来定义自己的类型。它们对于将相关数据分组很有用。
struct
可以在contract
外部声明,并在另一个contract
中导入。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
struct MyTodoStruct{
string text;
bool completed;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
import "./MyTodo.sol";
// 跟enum一样, 都可以通过外部引入.
contract Todos {
struct Todo {
string text;
bool completed;
}
Todo[] public todos;
function create(string calldata _text) public {
// 3 ways to initialize a struct
// - calling it like a function
todos.push(Todo(_text,false));
// key value mapping
todos.push(Todo({text: _text, completed: false}));
// initialize an empty struct and then update it
Todo memory todo;
todo.text = _text;
// todo.completed initialied tofalse
todos.push(todo);
}
// Solidity automatically created a getter for 'todos' so
// you don't actually need this function.
function get(uint _index) public view returns(string memory text, bool completed){
Todo storage todo = todos[_index];
return (todo.text, todo.completed);
}
function updateText(uint _index, string calldata _text) public {
Todo storage todo = todos[_index];
todo.text = _text;
}
function toggleCompleted(uint _index) public {
Todo storage todo = todos[_index];
todo.completed = !todo.completed;
}
}
Data Locations - Storage, Memory and Calldata
变量声明为storage
、memory
或calldata
,以显式指定数据的位置。
storage
变量是一个状态变量(存储在区块链上)memory
变量在内存中,当函数被调用时它才存在calldata
包含函数参数的特殊数据位置. Calldata arrays are read-only.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract DataLocations {
uint[] public arr;
mapping(uint => address) map;
struct MyStruct {
uint foo;
}
mapping(uint => MyStruct) myStructs;
function f() public {
// call _f with state variables
_f(arr, map, myStructs[1]);
// get a struct from a mapping
MyStruct storage myStruct = myStructs[1];
// create a struct in memory
MyStruct memory myMemStruct = MyStruct(0);
}
function _f(
uint[] storage _arr,
mapping(uint => address) storage _map,
MyStruct storage _myStruct
) internal {
// do something with storage variables
}
// You can return memory variables
function g(uint[] memory _arr) public pure returns (uint[] memory) {
// do something with memory array
for(uint i = 0; i < _arr.length; i++){
unchecked{_arr[i] -= 1;}
}
return _arr;
}
uint[] public _arrh;
function h(uint[] calldata _arr) external {
// do something with calldata array
// 修改的时候:TypeError: Calldata arrays are read-only.
for(uint i = 0; i < _arr.length; i++){
_arrh.push(_arr[i]);
}
}
}
注意输入数组的方式. ["1","2","3"]
或者[1,2,3]
才行
Function
有几种方法可以从函数返回输出。
公共(public, external)函数不能接受某些数据类型(比如map)作为输入或输出
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
contract Function {
// Functions canreturn multiple values.
function returnMany() public pure returns(uint, bool, uint){
return (1, true, 2);
}
// Return values can be named.
function named() public pure returns(uint x, bool b, uint y){
return (1, true, 2);
}
// Return values can be assigned to their name.
// In this case the return statement can be omitted.
function assigned() public pure returns(uint x, bool b, uint y){
x = 1;
b = true;
y = 2;
}
// Use destructuring assignment when calling another
// function that returns multiple values.
function destructuringAssignments()
public
pure
returns(uint, bool, uint, uint, uint){
(uint i,bool b,uint j)= returnMany();
// values can be left out.
(uint x, , uint y) = (4,5,6);
return (i,b,j,x,y);
}
// Cannot use map for either input or output
// Can use array for input
function arrayInput(uint[] memory _arr) public {}
// Can use array for output
uint[] public arr;
function arrayOutput() public view returns(uint[] memory){
return arr;
}
}
contract XYZ {
function someFunWithManyInput(
uint x,
uint y,
uint z,
address a,
bool b,
string memory c
) public pure returns (uint) {}
function callFunc() external pure returns(uint) {
return someFunWithManyInput(1, 2, 3, address(0), true, "c");
}
function callFuncWithKeyValue() external pure returns (uint){
return
someFunWithManyInput({a: address(0), b: true, c: "c", x: 1, y: 2, z: 3});
}
}
View and Pure
Getter
类型的函数可以声明为view
或pure
view
函数声明状态不会被改变pure
函数声明不改变或读取状态变量。
Remix IDE会告诉你什么时候用哪个关键词.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract ViewAndPure {
uint public x = 1;
// Promise not to modify the state.
function addToX(uint y) public view returns (uint) {
return x + y;
}
// Promise not to modify or read from the state.
function add(uint i, uint j) public pure returns (uint) {
return i + j;
}
}
Error
error
将撤销在transaction
期间对state
所做的所有更改。
可以通过调用require、revert或assert抛出错误。
- require用于在执行之前验证输入和条件。
- revert类似于require。有关详细信息,请参阅下面的代码。
- assert用于检查不应该为false的代码。断言失败可能意味着存在错误。
使用自定义错误(custom error
, 0.8版本新特性)来节省燃气。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
contract Error {
function testRequire(uint _i) public pure {
// Require should be used to validate conditions such as:
// - inputs
// - conditions before execution
// - return values from calls to other functions
require(_i > 10, "input must be greater than 10");
}
function testRevert(uint _i) public pure {
// Revert is useful when the condition to check is complex.
// This code does the exact same thing as the example above
if(_i <= 10){
revert("input must be greater than 10");
}
}
uint public num;
function testAssert() public view {
// Assert should only be used to test for internal errors,
// and to check invariants.
// Here we assert that num is always equal to 0
// since it is impossible to update the value of num
assert(num == 0);
}
error InsufficientBalance(uint balance, uint withdrawAmonut);
function testCustomError(uint _withdrawAmount) public view {
uint bal = address(this).balance;
if(bal < _withdrawAmount){
// 测试可以用0和1去看输出的区别
revert InsufficientBalance({balance: bal, withdrawAmonut: _withdrawAmount});
}
}
}
标签:function,学习,return,text,Solidity,语法,returns,uint,public
From: https://www.cnblogs.com/joey-redfield/p/17891087.html