在映射中,人們可以透過鍵( Key )來查詢對應的值( Value ),例如:透過一個人的 id 來查詢他的錢包位址。
聲明映射的格式為 mapping(_KeyType => _ValueType) ,其中 _KeyType 和 _ValueType 分別是 Key 和 Value 的變數類型。例子:
mapping(uint => address) public idToAddress; // id映射到地址
mapping(address => address) public swapPair; // 币对的映射,地址到地址
映射的規則:
-
規則1:
映射的 _KeyType 只能選擇Solidity內建的值類型,例如 uint , address 等,不能用自訂的結構體。而 _ValueType 可以使用自訂的類型。下面這個例子會報錯,因為 _KeyType 使用了我們自訂的結構體:
struct Student{ uint256 id; uint256 score; } mapping(Student => uint) public testVar;
mapping(uint => address) public idToAddress; mapping(address => address) public swapPair; function writeMap (uint _Key, address _Value) public{ idToAddress[_Key] = _Value; } // 初始值 🕵️ 0x0000000000000000000000000000000000000000
-
映射的原理
-
原理1: 映射不储存任何键(Key)的资讯,也没有length的资讯。
-
原理2: 映射使用keccak256(abi.encodePacked(key, slot))当成offset存取value,其中slot是映射变量定义所在的插槽位置。
-
原理3: 因为Ethereum会定义所有未使用的空间为0,所以未赋值(Value)的键(Key)初始值都是各个type的默认值,如uint的默认值是0。
-
所有值的初始值如下:
bool public _bool; // false
string public _string; // ""
int public _int; // 0
uint public _uint; // 0
address public _address; // 0x0000000000000000000000000000000000000000
enum ActionSet { Buy, Hold, Sell}
ActionSet public _enum; // 第1个内容Buy的索引0
function fi() internal{} // internal空白函数
function fe() external{} // external空白函数
// Reference Types
uint[8] public _staticArray; // 所有成员设为其默认值的静态数组[0,0,0,0,0,0,0,0]
uint[] public _dynamicArray; // `[]`
mapping(uint => address) public _mapping; // 所有元素都为其默认值的mapping
// 所有成员设为其默认值的结构体 0, 0
struct Student{
uint256 id;
uint256 score;
}
Student public student;
// delete操作符
bool public _bool2 = true;
function d() external {
delete _bool2; // delete 会让_bool2变为默认值,false
}
bytes1 // 0x00
constant
(常數)和 immutable
(不變量)。
狀態變數宣告這兩個關鍵字之後,在初始化後不能更改數值。
這樣做的好處是提升合約的安全性並節省gas。
constant
// constant 变量必须在声明的时候初始化,之后不能改变
uint256 constant CONSTANT_NUM = 10;
string constant CONSTANT_STRING = "0xAA";
bytes constant CONSTANT_BYTES = "WTF";
address constant CONSTANT_ADDRESS = 0x0000000000000000000000000000000000000000;
immutable
// immutable 变量可以在constructor里初始化,之后不能改变
uint256 public immutable IMMUTABLE_NUM = 9999999999;
address public immutable IMMUTABLE_ADDRESS;
uint256 public immutable IMMUTABLE_BLOCK;
uint256 public immutable IMMUTABLE_TEST;
constructor() {
IMMUTABLE_ADDRESS = address(this);
IMMUTABLE_NUM = 1118;
IMMUTABLE_TEST = test();
}
只有數值變數可以宣告 constant 和 immutable;string 和 bytes 可以宣告為constant,但不能為immutable。
下列哪一个变量不适合用 constant 或 immutable 来修饰?
答案:合約的ETH餘額 看到這題有點遲疑後面想想的確是 哈哈
控制 Solidity的控制流程與其他語言類似,主要包含以下幾種:
if-else
function ifElseTest(uint256 _number) public pure returns(bool){
if(_number == 0){
return(true);
}else{
return(false);
}
}
for
function forLoopTest() public pure returns(uint256){
uint sum = 0;
for(uint i = 0; i < 10; i++){
sum += i;
}
return(sum);
}
while
function whileTest() public pure returns(uint256){
uint sum = 0;
uint i = 0;
while(i < 10){
sum += i;
i++;
}
return(sum);
}
do-while
function doWhileTest() public pure returns(uint256){
uint sum = 0;
uint i = 0;
do{
sum += i;
i++;
}while(i < 10);
return(sum);
}
三元运算符
三元運算子是Solidity中唯一一個接受三個運算元的運算符,規則条件? 条件为真的表达式:条件为假的表达式。此運算子經常用作if語句的捷徑。
// 三元运算符 ternary/conditional operator
function ternaryTest(uint256 x, uint256 y) public pure returns(uint256){
// return the max of x and y
return x >= y ? x: y;
}
另外還有 continue
(立即進入下一個循環)和 break
(跳出目前循環)關鍵字可以使用。
90%以上的人用Solidity寫插入演算法都會出錯。
排序: Solidity中最常用的變數類型是 uint,也就是正整數,取到負值的話,會報 underflow 錯誤。而在插入演算法中,變數j有可能會取到-1,造成報錯。
這裡,我們需要把j加1,讓它無法取到負值。正確代碼:
// 插入排序 正确版
function insertionSort(uint[] memory a) public pure returns(uint[] memory) {
// note that uint can not take negative value
for (uint i = 1;i < a.length;i++){
uint temp = a[i];
uint j=i;
while( (j >= 1) && (temp < a[j-1])){
a[j] = a[j-1];
j--;
}
a[j] = temp;
}
return(a);
}
构造函数
合約部署的時候第一個做的事情,如下初始化 owner;
address public owner;
constructor() public {
owner = msg.sender;
}
修饰器 modifier
如下:
// 定义modifier
modifier onlyOwner {
require(msg.sender == owner); // 检查调用者是否为owner地址
_; // 如果是的话,继续运行函数主体;否则报错并revert交易
}
配合
function changeOwner(address _newOwner) external onlyOwner{
owner = _newOwner; // 只有owner地址运行这个函数,并改变owner
}