The term bytes in Solidity represents a dynamic array of bytes. It’s a shorthand for byte[] . */ bytes1 a = 0xb5; bytes1 b = 0x56;
// Default values // Unassigned variables have a default value bool public defaultBoo; // false uint256 public defaultUint; // 0 int256 public defaultInt; // 0 address public defaultAddr; // 0x0000000000000000000000000000000000000000
位置
本地
在函数体中定义。
不存储在链上。
链上
在函数体外定义。
在链上存储。
全局
提供关于区块链的信息。
1 2 3
// Here are some global variables uint256 timestamp = block.timestamp; // Current block timestamp address sender = msg.sender; // address of the caller
常量
常量是不能修改的变量。
它们的值是硬编码的,使用常量可以节省gas成本。
1 2 3 4
// coding convention to uppercase constant variables address public constant MY_ADDRESS = 0x777788889999AaAAbBbbCcccddDdeeeEfFFfCcCc; uint256 public constant MY_UINT = 123;
不可变常量
不可变变量就像常量。不可变变量的值可以在构造函数内部设置,但之后不能修改。
1 2 3 4 5 6 7 8 9 10 11 12 13
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24;
contract Immutable { // coding convention to uppercase constant variables address public immutable MY_ADDRESS; uint256 public immutable MY_UINT;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24;
contract SimpleStorage { // State variable to store a number uint256 public num;
// You need to send a transaction to write to a state variable. function set(uint256 _num) public { num = _num; }
// You can read from a state variable without sending a transaction. function get() public view returns (uint256) { return num; } }
以太币和wei
交易需要花掉以太币,以太币和wei的换算关系。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24;
contract EtherUnits { uint256 public oneWei = 1 wei; // 1 wei is equal to 1 bool public isOneWei = (oneWei == 1);
uint256 public oneGwei = 1 gwei; // 1 gwei is equal to 10^9 wei bool public isOneGwei = (oneGwei == 1e9);
uint256 public oneEther = 1 ether; // 1 ether is equal to 10^18 wei bool public isOneEther = (oneEther == 1e18); }
Gas
You pay gas spent * gas price amount of ether, where
gas is a unit of computation
gas spent is the total amount of gas used in a transaction
gas price is how much ether you are willing to pay per gas
Transactions with higher gas price have higher priority to be included in a block.
Unspent gas will be refunded.
There are 2 upper bounds to the amount of gas you can spend
gas limit (max amount of gas you’re willing to use for your transaction, set by you)
block gas limit (max amount of gas allowed in a block, set by the network)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24;
contract Gas { uint256 public i = 0;
// Using up all of the gas that you send causes your transaction to fail. // State changes are undone. // Gas spent are not refunded. function forever() public { // Here we run a loop until all of the gas are spent // and the transaction fails while (true) { i += 1; } } }
数据结构
Mapping
Maps are created with the syntax mapping(keyType => valueType).
The keyType can be any built-in value type, bytes, string, or any contract.
valueType can be any type including another mapping or an array.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24;
contract Mapping { // Mapping from address to uint mapping(address => uint256) public myMap;
function get(address _addr) public view returns (uint256) { // Mapping always returns a value. // If the value was never set, it will return the default value. return myMap[_addr]; }
function set(address _addr, uint256 _i) public { // Update the value at this address myMap[_addr] = _i; }
function remove(address _addr) public { // Reset the value to the default value. delete myMap[_addr]; } }
contract NestedMapping { // Nested mapping (mapping from address to another mapping) mapping(address => mapping(uint256 => bool)) public nested;
function get(address _addr1, uint256 _i) public view returns (bool) { // You can get values from a nested mapping // even when it is not initialized return nested[_addr1][_i]; }
function set(address _addr1, uint256 _i, bool _boo) public { nested[_addr1][_i] = _boo; }
function remove(address _addr1, uint256 _i) public { delete nested[_addr1][_i]; } }
Array
Array can have a compile-time fixed size or a dynamic size.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24;
contract Array { // Several ways to initialize an array uint256[] public arr; uint256[] public arr2 = [1, 2, 3]; // Fixed sized array, all elements initialize to 0 uint256[10] public myFixedSizeArr;
function get(uint256 i) public view returns (uint256) { return arr[i]; }
// Solidity can return the entire array. // But this function should be avoided for // arrays that can grow indefinitely in length. function getArr() public view returns (uint256[] memory) { return arr; }
function push(uint256 i) public { // Append to array // This will increase the array length by 1. arr.push(i); }
function pop() public { // Remove last element from array // This will decrease the array length by 1 arr.pop(); }
function getLength() public view returns (uint256) { return arr.length; }
function remove(uint256 index) public { // Delete does not change the array length. // It resets the value at index to it's default value, // in this case 0 delete arr[index]; }
function examples() external { // create array in memory, only fixed size can be created uint256[] memory a = new uint256[](5); } }
例子1:将数组中脚标处的某个元素删除。(将数组整体前移)
1 2 3 4 5 6 7 8
function remove(uint256 _index) public { require(_index < arr.length, "index out of bound");
for (uint256 i = _index; i < arr.length - 1; i++) { arr[i] = arr[i + 1]; } arr.pop(); }
例子2:将数组中脚标处的某个元素删除。(将数组看做一个set,删除后不保证数组的顺序)
1 2 3 4 5 6
function remove(uint256 index) public { // Move the last element into the place to delete arr[index] = arr[arr.length - 1]; // Remove the last element arr.pop(); }
Enum
Solidity supports enumerables and they are useful to model choice and keep track of state.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.24;
contract Todos { struct Todo { string text; bool completed; }
// An array of 'Todo' structs 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 initialized to false
todos.push(todo); }
// Solidity automatically created a getter for 'todos' so // you don't actually need this function. function get(uint256 _index) public view returns (string memory text, bool completed) { Todo storage todo = todos[_index]; return (todo.text, todo.completed); }
// update text function updateText(uint256 _index, string calldata _text) public { Todo storage todo = todos[_index]; todo.text = _text; }
// update completed function toggleCompleted(uint256 _index) public { Todo storage todo = todos[_index]; todo.completed = !todo.completed; } }
数据位置
Variables are declared as either storage, memory or calldata to explicitly specify the location of the data.
storage - variable is a state variable (store on blockchain)(链上,修改需要花gas)
memory - variable is in memory and it exists while a function is being called
calldata - special data location that contains function arguments(只读)