起因是Xenc師傅給我截了張圖,我日 居然看不懂 ,一搜才知道,之前學的版本有些老了.. 這次學下新一點的記錄下
HelloWorld
pragma solidity ^0.6.0; // version
contract One{
// 狀態變量
string name;
function setName() public{ // 必須要加權限修飾符了
name = "Muxue";
}
// view修飾的函數 表示訪問狀態變量, 但是不會修改, 不會消耗任何資源
function getName() public view returns(string memory){ // 返回字符串類型也需要加memory了
return name;
}
// pure修飾的函數 不不修飾也不讀取狀態變量 不會消耗任何資源
function pureTest() public pure returns(string memory){
return "test";
}
}
變量 常量 標識符 關鍵字
變量
type name = value;
標識符
需要命名的地方都是標識符
標識符命名規則
1. 字符, 數字, _, $組成
2. 不能以數字開頭
3. 區分大小寫
數據類型
基本類型
- 布爾(bool)
- 整形(int / uint)
- 地址(address)
- 定長字節數組
- 定長浮點(fixed / ufixed)
- 枚舉類型(enum)
- 函數類型(function)
引用類型
- 數組(array) {不定長字節數組, 字符串}
- 結構體(struct)
- 映射(mapping)
區別
值類型一般都是值拷貝傳遞,但引用類型 有些是地址傳遞
數組
全局數組
全局的是storage
Array
幾種聲明 初始化方式
pragma solidity ^0.6.0;
contract ArrayTest{
uint[4] arr1; // 固定數組的聲明
uint[] arr2; // 動態長度數組的聲明
// 聲明並初始化
uint[2] arr3 = [1,2];
uint[] arr4 = [1,4,12,4,2];
// 使用new
uint[] public arr5 = new uint[](3);
}
length和push pop的講解
length: 長度 修改length 可改變動態長度數組的長度,但是0.6.0以上的版本都不能使用length修改數組長度
push:固定數組不能用 動態數組storage可以用 memory不能用
pop: 把push進來的數據 再頂出去
pragma solidity ^0.6.0;
contract ArrayTest{
uint[] arr4 = [1,4,12,4,2];
// 使用new
uint[] public arr5 = new uint[](3);
function push() public{
arr5.push(1);
}
// 嘗試使用修改length
function changeLength() public{
// arr4.length = 12; // browser/Array/1.sol:19:9: TypeError: Member "length" is read-only and cannot be used to resize arrays. arr4.length = 12; // ^---------^
}
function Get() view public returns(uint[] memory){
return arr5;
}
function pop() public{
arr5.pop(); // 把push進來的再推出去
}
}
局部數組
局部的是memory
注意的一點是 新版本的 局部的都要加memory
,包括返回數組 返回值那里
pragma solidity ^0.6.0;
contract ArrayTest{
function test() public returns(uint[] memory){
uint[] memory arr8 = new uint[](3); // 使用new方法創建局部數組
arr8[0] = 1;
return arr8;
}
}
數據存儲位置
storage
:是存在區塊鏈 上的,全局變量
哪些數組類型可以使用storage
- 數組
- 結構體
- 映射
memory
:是存在內存上的,函數內的 局部的變量
棧
:值類型的局部變量存儲在這里
calldata
:當函數為外部函數(external
),如果此函數的參數(非返回參數),則參數要求必須用calldata
,(教程里是這樣說的,但是我用memory
也沒報錯)
對於存儲型的數組(storage
), 可以放任意的元素類型
對於內存性的數組(memory
), 元素不可以是映射類型mapping
storage和memory的相互轉換
pragma solidity ^0.6.0;
contract testFunc{
uint[] public a1Storage = [1,2,3];
function Geta1() public view returns(uint[] memory){
return a1Storage;
}
// sotrage -> memory 值傳遞 不會修改storage的值
function storageTomemory() public view{
uint[] memory b = a1Storage; // storage 賦值給 memory
b[0] = 100;
}
// memory -> storage 值傳遞
function memoryTostorage() public{
uint8[4] memory c = [2,4,1,5];
a1Storage = c;
c[0] = 255;
}
// sotrage -> storage 引用傳遞 修改一個 原數據也會修改數據
function storageTostorage() public{
uint[] storage m = a1Storage;
m[1] = 123;
}
// memory -> memory 引用傳遞
function memoryTomemory() public view returns(uint8[3] memory){
uint8[3] memory a = [1,2,3];
uint8[3] memory b = a;
b[1] = 12;
return a;
}
}
簡單來說兩個相同的都是引用傳遞,不同的都是值傳遞
字節數組
也分為
- 變長字節數組
- 定長字節數組
bytes
: 變成字節數組
bytes+num
:后面跟數字的是定長字節數組
pragma solidity ^0.6.0;
contract Test{
bytes b1; // 變長字節數組 bytes里是以16進制存儲值的
bytes b2 = "abc\x22\x25"; // \x后面就代表是十六進制的值
bytes b3 = "ce\u8bd5";
function Get() public view returns( bytes memory){
return b3;
}
bytes4 bt = 0x74657374; // 定長字節數組
}
定長字節數組轉變長字節數組
pragma solidity ^0.6.0;
contract Test{
bytes4 bt = 0x74657374; // 定長字節數組
// 把定長字節數組轉換成變長字節數組
function To() public view returns(bytes memory){
bytes memory temp = new bytes(bt.length);
for(uint i=0;i<bt.length;i++){
temp[i] = bt[i];
}
return temp;
}
}
string
string沒啥好說了吧 我擦..
字節轉字符串
pragma solidity ^0.6.0;
contract Test{
bytes public name = "慕雪";
function EchoName() public view returns(string memory){
return string(name);
}
}
Solidity交易和內置對象
提到交易不得不提Gas
了哈,也就是燃料也叫手續費
Gas
又分為兩個:
gas price
每個gas
的價格gas limit
限制gas
的最大值
需要給礦工預付的
gas
=gas price
*gas limit
消息:不修改合約狀態,如帶有pure
,view
等關鍵字的
賬戶和地址
分為外部賬戶
和合約賬戶
, 外部賬戶地址
, 外部合約地址
也就是外部賬戶和外部合約都各有地址
外部賬戶:我們錢包的一個用戶 給你一個地址 就是一個外部賬戶
合約賬戶:我們部署一個合約 都會給我們一個地址
地址
address
- 20個字節,160位
- 值類型
address payable
0.5.0以后出的
只能使用它來進行轉賬
屬性
balance
函數
專門用來做交易的
transfer
send
不會提示錯誤
demo code
pragma solidity ^0.6.0;
contract Test{
function echoAddress() public view returns(uint){
address _address = 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4;
return uint(_address);
}
function getBalance(address _account) public view returns(uint){
return _account.balance;
// return address(this).balance; 返回當前合約賬戶余額
// this是指當前合約賬戶
}
function getThis() public view returns(address){
return address(this);
}
function testTransfer() public payable{
address(this).transfer(msg.value); // 前面是要給哪個地址轉賬的地址
}
function testTransfer2() public payable{
address payable _address = address(this); // 轉賬必須加payable
_address.transfer(1 ether); // 雖然這里寫1了 但是我們還是需要在value那里設置1 ether
}
function testSend() public payable{
address payable _address = address(this);
_address.send(1 ether);
}
fallback() payable external{ // 回退函數
}
receive() payable external{
}
}
transfer
和send
的區別:
transfer假如value和設置的值不同 會報錯。而send不會,但會返回一個false,但是錯誤了 還是會扣錢
Solidity單位和全局變量
具體可以看
https://solidity-cn.readthedocs.io/zh/develop/units-and-global-variables.html?highlight=全局#id3
區塊鏈和交易屬性
pragma solidity ^0.6.0;
contract One{
/*
block.blockhash(uint blockNumber) returns (bytes32):指定區塊的區塊哈希——僅可用於最新的 256 個區塊且不包括當前區塊;而 blocks 從 0.4.22 版本開始已經不推薦使用,
由 blockhash(uint blockNumber) 代替
block.number (uint): 當前區塊號
msg.data (bytes): 完整的 calldata
msg.gas (uint): 剩余 gas - 自 0.4.21 版本開始已經不推薦使用,由 gesleft() 代替
msg.sig (bytes4): calldata 的前 4 字節(也就是函數標識符)
msg.value (uint): 隨消息發送的 wei 的數量
tx.gasprice (uint): 交易的 gas 價格
tx.origin (address): 交易發起者(完全的調用鏈)
*/
function getBlockHash() public view returns(bytes32){
return blockhash(block.number-1); // block.number 當前區塊號,得-1 要不然獲取不到hash
}
// block.coinbase (address): 挖出當前區塊的礦工地址
function getBlockCoinbase() public view returns(address){
return block.coinbase;
}
// block.difficulty (uint): 當前區塊難度
function getBlockDifficulty() public view returns(uint){
return block.difficulty;
}
// block.gaslimit (uint): 當前區塊 gas 限額
function getBlockLimit() public view returns(uint){
return block.gaslimit;
}
// block.timestamp (uint): 自 unix epoch 起始當前區塊以秒計的時間戳
function getBlockTimestamp() public view returns(uint){
return block.timestamp;
}
// gasleft() returns (uint256):剩余的 gas
function getGasleft() public view returns(uint){
return gasleft();
}
// now (uint): 目前區塊時間戳(block.timestamp)
function getTime() public view returns(uint){
return now;
}
// msg.sender (address): 消息發送者(當前調用)
function GetMsgsender() public view returns(address){
return msg.sender;
}
}
錯誤處理
最常用的應該就是require
了吧
pragma solidity ^0.6.0;
contract Two{
uint public money;
address master;
constructor() public{ // 構造函數
master = msg.sender;
}
function changeMoney() public {
require(msg.sender == master); // 如果不是 就直接報錯了 不會往下面走
money += 5000;
}
}
函數
也就是function
,已經非常熟悉了
可見性
public
:內部 外部都可調用,狀態變量和函數都可以用private
:私有的 只有內部可以調用,狀態變量和函數都可以用internal
:只有內部可以調用,狀態變量和函數都可以用external
:只有外部可以調用,只有函數可以用
可以明顯的看出 被
private
和internal
修飾的函數 外部不可以調用
被external
修飾的內部不可以調用
如要調用可以加一個this.
function test3() public view returns(uint) {
return this.testExternal();
}
調用方式
external
:外部的 也就是外部點擊函數名稱那種方式internal
:內部的 就是一個合約方法調用另一個方法唄
可變性 可修改性
pure
:不用狀態變量的時候view
:需要用到狀態變量payable
:需要付款的時候constant
:和view一樣的,0.5.0以后舍棄了
返回值
pragma solidity ^0.6.0;
contract Two{
// 返回多個參數
function test1() public pure returns(uint a,uint b){
return (2,4);
}
// 寫參數名字
function test2() public pure returns(uint sum){
sum = 1+2; // 不需要加類型 因為上面我們定義了
// 不用reutrn 要是return,以return的值為結果
}
}
get
被public
修飾的變量,系統默認寫了一個同名的函數,用來獲取值,0.5.0以上的版本 不支持重寫了
修改器 modifier
作用:可以修改函數的行為,控制函數的邏輯,代碼重用
pragma solidity ^0.6.0;
contract TestModifier{
uint public a;
// create modifier
modifier myModifier(){
a=1;
_; // 函數會到這
a=10;
}
// call modifier
function callModifier() public myModifier{
a=9; // 最終結果為10
}
}
帶參數的modifier
來個demo
看看modifier
的強大之處
pragma solidity ^0.6.0;
contract Two{
uint public level;
string public name;
string public sex;
modifier levelRequire(uint _level) {
require(level>=_level);
_;
}
function setLevel(uint _num) public{
level = _num;
}
function setName() public levelRequire(5){ // 相當於level需要大於或者等於五級才可以調用此方法
name = "Muxue"; // 如果modifier的_;后面還有 會在當前代碼后面執行
}
function setSex() public levelRequire(7){
sex = "male";
}
}
多重modifier的執行順序
這個是有點東西的
contract Three{
uint public a = 1;
modifier Test1{
a = 2; // 執行順序1
_; // 把Test2帶進來
a = 3; // 執行順序5 也就是最后一個
}
modifier Test2{
a = 4; // 執行順序2
_; // 把test函數帶進來
a = 5; // 執行順序4
}
function test() public Test1 Test2{
a = 6; // 執行順序3
// a的結果為3
}
}
如果不信的 可以debug一步步的調着看
合約
構造函數
- 合約創建時自動調用,且只調用一次。每個合約只能有一個構造函數
- 構造函數一般是為狀態變量初始化
constructor
關鍵字- 分為有參和無參
pragma solidity ^0.6.0;
contract TestNewContract{
uint age;
constructor(uint _age) public{
age = _age;
}
}
封裝性
-
函數合約
-
修飾符(訪問修飾符)
-
public
,private
,internal
,external
- 狀態變量:
public
,private
,internal
- 函數:
public
,private
,internal
,external
- 狀態變量:
-
繼承
is
關鍵字
pragma solidity ^0.6.0;
contract Father{
address owner;
string name;
uint money = 100000000000000000000000;
constructor() public{
owner = msg.sender;
name = "Muxue";
}
function changeName(string memory _name ) public{
require(msg.sender == owner);
name = _name;
}
}
contract Son is Father{
function getMoney() public view returns(uint){
return money; // 繼承的父親的
}
}
父合約構造函數的傳參
pragma solidity ^0.6.0;
contract Father{
uint private age;
constructor(uint _age) public{
age = _age;
}
}
contract Son is Father(46){ // 繼承式
}
// 這兩種方法不能同時使用
contract Son2 is Father{
constructor() Father(46) public{ // 修改風格式
}
}
多態
重寫父類方法和狀態變量
得在父類方法上加上virtual
關鍵字,子類重寫的方法加上override
方法
pragma solidity ^0.6.0;
contract A{
function F() public pure virtual returns(string memory){ // 僅當函數被標記為 virtual 或在接口中定義 時,才可以覆蓋
return "A";
}
}
contract B is A{
// 函數重寫
function F() public pure override returns(string memory){ // override 代表可重寫
return "B";
}
// 函數重載
function F(string memory _test) public pure returns(string memory){
return _test;
}
}
父類:
virtual
,子類:override
重寫要保證,函數名,參數,返回值相同
重寫狀態變量
0.6.0
后 不可再重寫狀態變量
super
pragma solidity ^0.6.0;
contract A{
function F() public pure virtual returns(string memory){ // 僅當函數被標記為 virtual 或在接口中定義 時,才可以覆蓋
return "A";
}
function eat() public pure virtual returns(string memory){
return "rou";
}
}
contract B is A{
// 函數重寫
function F() public pure override returns(string memory){ // override 代表可重寫
return "B";
}
// 函數重載
function F(string memory _test) public pure returns(string memory){
return _test;
}
function eat() public pure override returns(string memory){
return "yu";
}
function test() public view returns(string memory){
// return eat(); // 調用的是自己重寫的那個方法
return super.eat(); // 調用父類eat方法
}
}
想要調用父類的,也可以用
父類名.方法名
super是內部調用
多重繼承 重寫父類方法
pragma solidity ^0.6.0;
contract Father{
function getMoney() public pure virtual returns(uint ){
return 10000;
}
}
contract Mother{
function getMoney() public pure virtual returns(uint ){
return 8000;
}
}
contract Son is Father,Mother{
function getMoney() public pure override(Father,Mother) returns(uint){ // 處理重名函數
return 18000;
}
}
這個在我編譯時,一直在報錯,但是我還不知道哪錯了,我用
0.8.4
編譯一次之后,沒問題。最后再換回0.6的版本,照樣可以編譯成功
抽象合約
抽象合約
- 關鍵字:
abstract
- 抽象合約中,可以有抽象函數,非抽象函數
- 抽象函數 不需要實現函數體
- 抽象合約不能實例化
作用:起到約束,約束繼承的抽象合約的子合約,必須重寫抽象函數
pragma solidity ^0.6.0;
abstract contract Father{ // 抽象合約 關鍵字 abstract
function eat() public pure virtual; // 抽象函數
}
contract Son is Father{
// 必須重寫函數
function eat() public pure override{
}
}
接口
- 關鍵字
interface
- 接口中所有的函數都是抽象函數,所有可以省略
virtual
關鍵字 - 接口函數的修飾符必須使用
external
- 其余限制:不能繼承其他合約或接口,不能定義構造函數,不能定義狀態變量,不能定義結構體
interface Father{ // 接口
function eat() external pure; // 沒有{}
}
contract Son is Father{
function eat() public pure override{ // 重寫eat方法
}
}
庫
作用
- 代碼重要性
- 將多個合約重復的代碼提取到一個庫中
- 不需要繼承 節省gas
關鍵字及特性
libray
- 庫中的函數不能修改狀態變量
- 庫不可以被銷毀
- 不能定義狀態變量
- 不可以繼承其他元素,也不能被繼承
- 庫不能接受以太幣
使用
有兩種方式
庫名.方法名
pragma solidity ^0.6.0;
library Search{ // 庫定義
function indexOf(uint[] storage _data,uint _value) public view returns(uint){
for(uint i=0;i<_data.length;i++){
if(_data[i] == _value){
return i;
}
}
return uint(-1);
}
}
contract TestLibray{ // 第一種
uint[] data;
constructor() public{
data.push(1);
data.push(2);
data.push(3);
data.push(4);
}
// 調用庫函數
function indexof(uint _value) public view returns(uint){
return Search.indexOf(data,_value);
}
}
using 庫名 for 狀態變量
pragma solidity ^0.6.0;
library Search{ // 庫定義
function indexOf(uint[] storage self,uint _value) public view returns(uint){ // self也就是傳過來的那個類型
for(uint i=0;i<self.length;i++){
if(self[i] == _value){
return i;
}
}
return uint(-1);
}
}
contract TestUsingFor{
using Search for uint[]; // 把search這個庫綁定為uint[]類型
uint[] data;
constructor() public{
data.push(1);
data.push(2);
data.push(3);
data.push(4);
}
// 調用庫函數
function indexof(uint _value) public view returns(uint){
return data.indexOf(_value); // 會自動把data傳給第一個參數
}
}
合約銷毀
合約生命周期
- 合約創建(new、sdk)
- 合約操作、使用(調用函數實現功能)
- 合約銷毀(區塊鏈上 關於合約的存儲和代碼都會被刪除)
pragma solidity ^0.6.0;
library Search{ // 庫定義
function indexOf(uint[] storage self,uint _value) public view returns(uint){ // self也就是傳過來的那個類型
for(uint i=0;i<self.length;i++){
if(self[i] == _value){
return i;
}
}
return uint(-1);
}
}
contract TestUsingFor{
using Search for uint[]; // 把search這個庫綁定為uint[]類型
uint[] data;
address owner;
constructor() public{
owner = msg.sender;
data.push(1);
data.push(2);
data.push(3);
data.push(4);
}
modifier onlyOwner() {
require(owner == msg.sender);
_;
}
// 調用庫函數
function indexof(uint _value) public view returns(uint){
return data.indexOf(_value); // 會自動把data傳給第一個參數
}
function kill() public onlyOwner{
selfdestruct(msg.sender); // 銷毀合約
}
}
映射
引用數據類型
關鍵字及特性
mapping
- 存儲一對數據,以
key-value
形式的 - key的數據類型是有要求的:動態數組,枚舉,
struct
,mapping
都不可以;value基本上都可以 mapping
不能作為參數使用
pragma solidity ^0.6.0;
contract TestMapping{
mapping(uint=>string) public uintMapping; // key:uint value:string
mapping(address=>uint) public addressMapping;
mapping(string=>mapping(uint=>address)) public stringMapping;
constructor() public{
uintMapping[1] = "test";
addressMapping[0x5B38Da6a701c568545dCfcB03FcB875f56beddC4] = 1;
addressMapping[0x17F6AD8Ef982297579C203069C1DbfFE4348c372] = 2;
stringMapping["Muxue"][1] = 0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB; // 復雜的是[key][key] = value;
}
}
結構體
引用數據類型
關鍵字及特性
- 關鍵字
struct
- 大部分類型都可以,但是不可以包含自己本身
- 結構體作為函數的返回值類型使用時
- 結構體中有
mapping
類型,函數只能使用internal
,private
- 結構體中沒有
mapping
類型,需要添加pragma experimental ABIEncoderV2;
- 結構體中有
contract TestStruct{
struct People{
uint id;
string name;
mapping(string=>uint) grade;
// People test;
}
People public pp;
constructor() public{
// People memory ppt = People(1,"Muxue"); // mapping類型不能直接賦值,因為是storage的
People memory ppt = People({name:"Muxue",id:1});
pp = ppt;
pp.grade["level"] = 1;
}
}
枚舉
- 作用:增強代碼的可讀性
- 基本數據類型
- 關鍵字:
enum
- 書寫時不能有
;
- 不能有
""
- 不能有中文
- 結果可以轉為
uint
contract TestEnum{
enum Sex{Man,Woman}
function useEnum() public pure returns(Sex){
return Sex.Man;
}
function useenum() public pure returns(uint){
return uint(Sex.Woman);
}
}
事件與日志
- 合約中不能直接訪問日志中的內容,可以通過sdk的方式進行交互 獲取
- 日志通過事件來實現
- Solidity中,事件是操作觸發行為,日志是觸發事件后將數據記錄在區塊鏈中
事件
事件可以用來做操作記錄,存儲為日志。主要就是用來記錄日志的
關鍵字:
event
:創建事件emit
:觸發事件
pragma solidity ^0.6.0;
contract TestEvent{
event LogEvent(string _name,uint _age); // 創建一個事件
function emitEvent() public{ // 不能加 pure or view
emit LogEvent("Muxue",17); // 觸發事件
}
}
事件的主題
- 將事件索引化
- 一個沒主題的事件,無法搜索到
- 一個事件,最多有4個主題
- 事件簽名
- 參數簽名
經過Keccak-256
算法加密
簡單來說:主題就是為了講事件索引化,可查詢到這個事件
pragma solidity ^0.6.0;
contract TestEvent{
event LogEvent(string indexed _name,uint indexed _age); // 創建一個事件
function emitEvent() public{ // 不能加 pure or view
emit LogEvent("Muxue",17); // 觸發事件
}
}
異常
- 程序編譯或運行中發生的錯誤 即異常
- 發生運行時異常,會將之前修改的狀態全部還原(0.6.0版本可以選擇)
- solidity異常
- 0.4.10之前,throw 條件不滿足,中斷運行,恢復修改的狀態,耗光gas
- 0.4.10之后,throw廢棄,
require()
,assert()
,revert()
代替原來的throw - 0.6.0版本,增加了
try catch
- 功能介紹
① 條件檢查
-require()
:還原狀態 返回gas
-assert()
:還原狀態 耗光gas
② 引發異常
-throw
:已經廢棄
-revert()
:與thorw的區別,允許返回錯誤原因,可以退回gas
③ 捕獲/處理異常
-try..catch
:只適合於外部調用,
pragma solidity ^0.6.0;
contract TestException{
uint public data = 100;
function testThrow(uint _i) public pure{
//if(_u<10) throw;
}
function testRequire(uint _i) public{
data = 200; // 假如下面引發異常了,會把修改的狀態還原回去
require(_i>10,"_i < 10");
}
function testAssert(uint _i) public{
data = 200; // 假如下面引發異常了,會把修改的狀態還原回去
assert(_i>10);
}
function testRevert(uint _i) public returns(uint){
data = 200; // 假如下面引發異常了,會把修改的狀態還原回去
if(_i<10){
revert("_i < 10");
}
return 12;
}
event successEvent();
event failEvent();
function testTry(uint _i) external returns(uint){
try this.testRevert( _i ) returns(uint _value){ // 某個函數可能會出現異常, 必須外部調用所以加this. 返回值需要定義一個變量
// 如果沒有異常走這個代碼塊
emit successEvent();
return _value;
}catch{
// 如果有異常走這個代碼塊
emit failEvent();
}
}
}
Solidity匯編
https://learnblockchain.cn/article/675
概念
solidity匯編語言,采用自己獨特的語言風格,使編寫的代碼可讀性更高,且能夠直接與EVM交互,而且可以減少gas的消耗】
分類
- 內聯匯編
- 獨立匯編
內聯匯編的作用
- 可以直接嵌入到solidity的源碼中使用
- 代碼的可讀性更高
- 直接訪問棧
- 可以節省gas
字面量
- 字符常量:10進制 16進制
- 字符串:"",字符串字面量最多可以包含32個字符
作用域
{}
離開大括號就不能用了
特點
函數式操作碼
pragma solidity ^0.6.0;
contract Test{
function TestSum(uint _n) public pure returns(uint _sum){
for(uint i=0;i<_n;i++){
_sum += i;
}
}
function TestAssembly(uint _n) public pure returns(uint){
assembly{
let sum := 0 // let定義變量 := 賦值
for{let i:=0} lt(i,_n) {i := add(i,1)}
{
sum := add(sum,i)
}
mstore(0x0,sum)
return(0x0,32)
}
}
}
匯編局部變量
訪問外部變量
pragma solidity ^0.6.0;
contract Test2{
uint outerV;
function outerValue() public pure{
uint innerV;
assembly{
let y := innerV // 只能訪問局部變量
let x := outerV // 不能訪問狀態變量
}
}
}
標簽
標簽已經廢棄掉了
流程控制
solidity沒有switch,但匯編中有
- 判斷:
①. if 沒有else
②. switch,做多選擇 - 循環
只有for
pragma solidity ^0.6.0;
contract Test3{
function testIf(uint _v) public pure returns(bool flag){
assembly{
flag := true
if lt(_v,5){
flag := false
}
}
}
function testSwitch(uint _n) public pure returns(uint _num){
assembly{
let z:=_n
switch z
case 1{
_num := 1
}
case 2{
_num := 2
}
case 3{
_num := 3
}
default{
_num := 100
}
}
}
}
函數
pragma solidity ^0.6.0;
contract Test4{
function test() public pure{
assembly{
function sum(a,b) -> res{
}
// 調用
let xx := sum(1,4)
}
}
}