上一篇已經將開發智能合約時會使用到的工具安裝好並學會基本知識,此篇開始會講解 Solidity 這個語言並實作智能合約。
圖片來源:維基百科
Solidiy 是一個合約導向的語言,是靜態語言,它的語法跟 JavaScript 有些相近,對於 JavaScript 的使用者而言,會比較容易上手,我認為這樣的設計,能夠促進 DApp 的開發,畢竟在語言的學習上成本相對較低!
網路上有 Solidity 的相關資料,但在閱讀時要看好版本,因為 Solidity 現階段還不夠穩定,會經常有變動,在不同版本可能會有語法上的差異,這邊我們會使用 0.5.0
版進行開發,是較新的版本。
那是不是應該要安裝 Solidity 的相關程式呢?在前一篇安裝 Truffle 的同時,就連同 Solidity 一起安裝了,所以不需要額外安裝囉
那廢話不多說,馬上進入 Solidity 基本結構!
在開頭第一行一定要先定義使用的 Solidity 版本,讓編譯器知道怎麼編譯智能合約,那要定義的話就使用 pragma
關鍵字,比較常見的定義方式如下,使用 ^
來定義 最低可接受版本數 。
pragma solidity ^0.5.0;
那也可以設定版本區間,方法很簡單且直觀,如下:
pragma solidity >=0.4.21 <0.6.0;
定義合約就像物件導向語言定義類別一樣,在物件導向語言裡定義類別用 class
,在 Solidity 裡定義合約用 contract
,並且可以設置 constructor
,如下:
pragma solidity ^0.5.0;
contract HelloWorld {
string public message;
constructor() public {
message = "HelloWorld";
}
}
從上方的範例程式碼可以發現, public
放在後方而不是前方,這個很重要,在 Solidity 中,定義 public
與 private
是寫在後方的!
constructor
可以有參數,只要在部署合約時,連同參數一同部署即可,如下:
pragma solidity ^0.5.0;
contract HelloWorld {
string public message;
constructor(string memory text) public {
message = text;
}
}
咦?為什麼參數裡面除了型別以外還多了個 memory
呢?嘿嘿,先小賣關子,請繼續往下看
在 Solidity 中,狀態變數就是在合約中的全域變數,會永久儲存在區塊鏈中的,所謂的「改變合約狀態」就是指「變更狀態變數」,狀態變數宣告如下:
pragma solidity ^0.5.0;
contract HelloWorld {
string public message;
}
了解狀態變數後就可以來說說 memory
以及 storage
。
storage
,有點類似全域變數的概念。以物件導向的角度來看,可以將函式看成是合約中的方法。
若有回傳值,將回傳值的型別寫在後方,使用 returns
保留字。
會用 修飾詞 來定義該函式是否有修改或讀取狀態變數,主要的目的是減少 Gas 的消耗,共分為兩種:
pragma solidity ^0.5.0;
contract HelloWorld {
string public message;
constructor(string memory text) public {
message = text;
}
function print(string memory name) public pure returns (string memory) {
return name;
}
function alert() public view returns(string memory) {
return message;
}
}
上方的範例就是一個簡單的 HelloWorld 合約了!那來進行合約的測試吧!
先將Ganache打開並且把HelloWorld合約編譯好,再來要設定部署檔,這邊我們直接修改 1_initial_migration.js
,並設定constructor
的參數,這邊範例參數為 HelloWorld! :
const HelloWorld = artifacts.require("HelloWorld");
module.exports = function(deployer) {
deployer.deploy(HelloWorld, 'HelloWorld!');
};
調整完畢後進行部署:
truffle migrate
接著就是重頭戲了,要使用 Truffle 的 console 模式來進行測試,輸入指令:
truffle console
此時會進入 console 模式,使用的語法為 JavaScript
,這邊我們先宣告一個變數待會用來存放合約實體:
let contract
接著要找出已部署的 HelloWorld 合約,並把合約實體存入 contract
變數中:
HelloWorld.deployed().then(instance => contract = instance)
把合約實體存入後,就可以呼叫合約中的函式,先呼叫 alert
函式:
contract.alert()
就會看到 HelloWorld! 字串,接著來測試 print
函式:
contract.print("HAO")
會看到 HAO 字串。
今天學習到智能合約撰寫的基本架構,如:版本定義、合約定義、 memory 與 storage 等,並且完成 HelloWorld 智能合約,還透過 Truffle 進行測試。
Solidity 中 storage 和 memory 的区别问题
當我在remix compile helloworld.sol時,他出現"browser/HelloWorld.sol:14:2: DeclarationError: Identifier already declared. function message() public view returns(string memory) { ^ (Relevant source part starts here and spans across multiple lines). browser/HelloWorld.sol:5:3: The previous declaration is here: string public message; ^-------------------^" 這個error.
抱歉,範例裡面重複命名 message
了,function 應該為 alert
,我馬上修正,謝謝提醒!