Lesson 2: Welcome to Remix! Simple Storage
第一行
Solidity 第一行用注釋來寫SPDX License Identifier
雖然是可選的,但是有些編譯器會出現(xiàn)警告
用來定義license和代碼分享規(guī)則
//SPDX-License-Identifier:MIT
MIT是限制最少的license之一,大多數(shù)代碼都是用MIT
第二行
solidity是一個更新迭代比較快的語言,因此sol文件第二行用來聲明版本
如下明確聲明了只使用0.8.7版本
pragma solidity 0.8.7; // 使用雙斜線進(jìn)行注釋,第一行是聲明使用solidity的版本
同時也可以在0.8.7前面添加一個^ 用來聲明此代碼運行環(huán)境能在0.8.7及之后運行
pragma solidity ^0.8.7;
如果用一個區(qū)間表示,用如下方式表示本代碼運行環(huán)境位于以下區(qū)間
pragma solidity >=0.8.7 <0.9.0; //表示0.8.7 0.8.8 0.8.9適用但0.9.0不適用
智能合約的開始
使用 contract
用來高速編譯器后面的代碼是定義智能合約的。contract
是智能合約的關(guān)鍵之之一。
類似于java 的 class
?
//SPDX-License-Identifier:MIT
pragma solidity 0.8.7; // 使用雙斜線進(jìn)行注釋,第一行是聲明使用solidity的版本
contract SimpleStorage {
}
值類型
類型
描述
運算符
bool
布爾類型 true、false
!
(邏輯非)&&
(邏輯與, “and” )||
(邏輯或, “or” )==
(等于)!=
(不等于)
int/uint
分別表示有符號和無符號的不同位數(shù)的整型變量。 支持關(guān)鍵字 uint8
到 uint256
(無符號,從 8 位到 256 位)以及 int8
到 int256
,以 8
位為步長遞增。 uint
和 int
分別是 uint256
和 int256
的別名。最大uint256,默認(rèn)也是uint256。通常開發(fā)時把分配空間寫出來。 uint8表示分配了8個bit,二進(jìn)制表示為11111111
8個1,所以最大能表示255。256就不能用uint8聲明了。
比較運算符:
<=
,<
,==
,!=
,>=
,>
(返回布爾值)位運算符:
&
,|
,^
(異或),~
(位取反)移位運算符:
<<
(左移位) ,>>
(右移位)算數(shù)運算符:
+
,-
, 一元運算負(fù)-
(僅針對有符號整型),*
,/
,%
(取余或叫模運算) ,**
(冪)
address
保存一個20字節(jié)的值(以太坊地址的大?。?/p>
address payable
可支付地址,與 address
相同,不過有成員函數(shù) transfer
和 send
舉例:
bool hasFavoriteNumber = true;
uint8 favoriteNumber = 123;
uint number = 123;
函數(shù)
//SPDX-License-Identifier:MIT
pragma solidity 0.8.7; // 使用雙斜線進(jìn)行注釋,第一行是聲明使用solidity的版本
contract SimpleStorage {
? ?int8 public number = 123;
? ?
? ?//函數(shù)
? ?function changeNumber (int8 _number) public {
? ? ? ?number = _number;
? ?}
}
函數(shù)用 function
聲明,類似于js。但要在后面跟一個訪問修飾符
一共有四個訪問修飾符
public
:內(nèi)部、外部均可見(參考為存儲/狀態(tài)變量創(chuàng)建 getter 函數(shù))private
:僅在當(dāng)前合約內(nèi)可見external
:僅在外部可見(僅可修飾函數(shù))——就是說,僅可用于消息調(diào)用(即使在合約內(nèi)調(diào)用,也只能通過this.func
的方式)internal
:僅在內(nèi)部可見。只有這個合約或集成他的合約能讀?。ㄒ簿褪窃诋?dāng)前 Solidity 源代碼文件內(nèi)均可見,不僅限于當(dāng)前合約內(nèi),譯者注)
變量的默認(rèn)訪問修飾符時 internal
gas消耗
執(zhí)行上面代碼后,可以在控制臺看到所消耗的gas是2472 gas

當(dāng)在函數(shù)中添加一行 number = number +1
時,執(zhí)行相同操作,可以看到消耗的gas增加了更多

solidity有兩個關(guān)鍵字,標(biāo)識函數(shù)調(diào)用不需要消耗gas。分別是 view
和 pure
。
在區(qū)塊鏈中,只有更改狀態(tài)的時候才支付gas,發(fā)起交易。
如下圖,number 和 review 是藍(lán)色,而 changeNumber是黃色,下圖中有g(shù)as

下面的number調(diào)用記錄就沒有g(shù)as一行

上圖中的 execution cost 2472 gas (Cost only applies when called by a contract)
表示調(diào)用這個函數(shù)所需要花費的gas
? ?function review() public view returns (int8){
? ? ? ?return number;
? ?}
view
表示只會讀取這個合約的狀態(tài)。如上面的review函數(shù),只能讀取number并返回。不允許修改任何狀態(tài)。pure
也不允許修改任何狀態(tài)。但 pure
還不允許讀取區(qū)塊鏈上的數(shù)據(jù)。所以用 pure
修飾不能讀取number。
pure
修飾的方法類似于下面,可能是常用的方法,或者是某個不需要讀取數(shù)據(jù)的算法。
function add() public pure returns (int256){
? ?return (1 + 1);
}
int8 public number = 123; //帶有public的變量可以看作是一個返回int8的view函數(shù)
結(jié)構(gòu)體
一個簡單的結(jié)構(gòu)體示例
//定義
struct People{
? ?int8 number;
? ?string name;
}
//使用
People public person1 = People({number:2,name:"furao"});
部署合約后,點擊 person1
可以看到

(在solidity中的結(jié)構(gòu)體可以先使用后聲明,同js一樣)
數(shù)組
//聲明一個動態(tài)數(shù)組(因為沒有規(guī)定他的大?。?People[] public peoples;
//如果在中括號里加一個數(shù)字,則聲明這個數(shù)組中大小是3,不可變
People[3] public peoples;
向數(shù)組中添加數(shù)據(jù)
? ?//定義
? ?struct People{
? ? ? ?int8 number;
? ? ? ?string name;
? ?}
? ?
? ?//聲明一個動態(tài)數(shù)組(因為沒有規(guī)定他的大小)
? ?People[] public peoples;
? ?//向數(shù)組中添加一個數(shù)據(jù)
? ?function addPerson (string memory _name,int8 _number) public {
? ? ? ?//寫法1
? ? ? ?People memory newPerson = People({name:_name,number:_number});
? ? ? ?peoples.push(newPerson);
? ? ? ?
? ? ? ?//寫法2 省略中間變量new Person
? ? ? ?peoples.push(People({name:_name,number:_number}));
? ? ? ?
? ? ? ?//寫法3 根據(jù)people屬性的順序直接添加。同java,但沒有new字
? ? ? ?peoples.push(People(_number,_name));
? ?} ? ?
? ?
將代碼放入編譯器,運行

memory、storage、calldata
上述 addPerson
方法中,聲明入?yún)⒌臅r候有一個 memory
進(jìn)行描述。如果刪了它,則會編譯報錯。
TypeError: Data location must be "memory" or "calldata" for parameter in function, but none was given.
目前在solodity中,有6種方式進(jìn)行存儲數(shù)據(jù)
stake
memory
storage
calldata
code
logs
臨時變量有 memory
和 calldata
,calldata
不能被修改(賦值)。memory
可以被修改。storage
是用永久變量。
?
? ?function addPerson (string memory _name,int8 _number) public {
? ? ? ?//比如在這里,用memory聲明的_name 可以被再次賦值
? ? ? ?_name = "cat";
? ? ? //如果使用calldata 聲明 _name, 則上句話會報錯
? ?} ? ?
? ?
那么在 addPerson
的入?yún)⒅?,為什?_number
不用 ?memory
或 calldata
修改?
data location
只適用于數(shù)組,結(jié)構(gòu)體或映射類型。因為 string
實際上是數(shù)組,所以需要用 datalocation
修飾
Mapping
功能同java的map
聲明和使用:
? ?//聲明一個mapping
? ?mapping(string => int8) public nameAndNumber;
? ?
? ?//使用
? ?function addPerson (string memory _name,int8 _number) public {
? ? ? ?nameAndNumber[_name] = _number;
? ?}
