スマートコントラクトプログラミング言語であるSolidityの関数について記載します。
Solidityの関数
Solidityでの関数は、プログラムのどこからでも呼び出すことができる再利用可能なコードのグループのことをさします。
関数があることによって、同じコードを何度も記述する必要がなくなります。
これは、Solidityプログラマがコードをモジュール化して作成するのに役立ちます。
関数を使用すると、プログラマは大きなプログラムをいくつかの小さくて扱いやすい関数に分割できます。
他の高度なプログラミング言語と同様に、Solidity 、関数を使用してコードをモジュール化するために必要なすべての機能もサポートしています。
今回は、Solidityの関数を作成する方法について説明します。
Solidityで関数を定義する方法
関数を使用する場合、関数定義をする必要があります。
Solidity で関数を定義する最も一般的な方法は、functionキーワードを使用することです。
その後に一意の関数名、引数(パラメーター)のリスト (空の場合もあります)、および{}(中かっこ)で囲まれたステートメントブロックに関数内で行いたい処理を記述する必要があります。
下記は、基本的なSolidityの関数の構文を示しています。
1 2 3 |
function function-name(parameter-list) scope returns() { //statements } |
下記スマートコントラクトのコードは、引数(パラメータ)を渡さない単純なFunctionSample関数を定義しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract FunctionSample { //関数を定義 function get() public view returns(uint){ uint x = 1; // ローカル変数xを定義し、1を設定 uint y = 2; // ローカル変数yを定義し、2を設定 // aとbを加算した結果をresultに格納 uint result = a + b; // resultを返す return result; } } |
このスマートコントラクトをDeployし、getファンクションを呼び出すと、下記値が表示されます。
Solidityで関数を呼び出す方法
コントラクト内のどこかで関数を呼び出すには、関数の名前を記述して呼び出す必要があります。
関数の呼び出す際に、さまざまなパラメーターを渡す機能があります。
渡されたパラメーターは関数内で使用でき、それらのパラメーターに対して任意の操作を実行できます。
関数はコンマで区切られた複数のパラメーターを受け取ることができます。
次のコードでは、Solidityの関数でどのように関数を呼び出すのか、引数の指定、受け取り方法を記載しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract CallFunctionSample { function check() public pure returns(string memory){ uint x = 1; uint y = 2; //ここで関数を呼び出して、関数からの結果をreturnしています。 return compare(x,y); } function compare(uint _x,uint _y) internal pure returns (string memory) { if (_x == _y) { return "a and b are same"; } return "a and b are not same"; } } |
このスマートコントラクトをDeployし、compareファンクションを呼び出すと、下記値が表示されます。
関数の戻り値 Returnステートメント
Solidityの関数には、オプションのreturnステートメントを含めることができます。
このReturnステートメントは、関数内の最後のステートメントである必要があります。
関数から値を返す場合にReturnステートメントが必要になりますが、返り値がない場合は省略可能です。
Solidity では、関数は複数の値を返すこともできます。以下の例を参照してください。
1 2 3 4 5 6 7 8 9 10 11 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract returnSample { function get() public pure returns(uint multiple, uint sum){ uint a = 1; uint b = 2; // a*bとa+bの結果を返す return(a*b, a+b); } } |
また、returnを省略し、下記のように変数名だけで返り値を表現することも可能です。
1 2 3 4 5 6 7 8 9 10 11 12 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract returnSample { function get() public pure returns(uint multiple, uint sum){ uint a = 1; uint b = 2; multiple = a * b; //a * bの結果を返却値としてmultipleに格納 sum = a + b; //a + bの結果を返却値としてsumに格納 } } |
このスマートコントラクトをDeployし、getファンクションを呼び出すと、下記のように配列の値が表示されます。
関数修飾子(modifier)
関数修飾子(modifier)は、関数に前提条件を追加し、関数の動作を変更するために使用されます。
パラメーター付きまたはパラメーターなしで修飾子を作成します。
以下のコードはmodifierを定義したスマートコントラクト例です。
まだ,modifierを呼び出す関数は記述していません。どのように定義するかをまずは確認してみてくだし。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract Owner { address public owner; // コントラクトを実行したアドレスをownerに設定するOwnableファンクション function Ownable() public { owner = msg.sender; } // 関係修飾子modifierを定義。 modifier onlyOwner { require(msg.sender == owner); //Call元の関数に戻る _; } // 関係修飾子modifierを定義。 modifier costs(uint price) { if (msg.value >= price) { //Call元の関数に戻る _; } } } |
modifierは、特殊記号である”_;“が出現する部分に関数本体が挿入される仕様となっています。
したがって、この関数を呼び出したときにmodifierの条件が満たされていれば関数が実行され、そうでない場合は例外が投げられます。
以下のソースコード例を見てください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.4.16 <0.9.0; contract Owner { address owner; // コントラクトを実行したアドレスをownerに設定するOwnableファンクション function Ownable() public { owner = msg.sender; } // 関係修飾子modifierを定義。 modifier onlyOwner { require(msg.sender == owner); //Call元の関数に戻る _; } // 関係修飾子modifierを定義。 modifier costs(uint price) { if (msg.value >= price) { //Call元の関数に戻る _; } } } contract Register is Owner { //addressをKey,boolをvalueのregisteredAddressesマッピングを定義 mapping (address => bool) registeredAddresses; uint public price; //呼び出されたときにのみ実行されるconstructorでinitialPriceを受け取り,priceに設定 constructor(uint initialPrice) public { price = initialPrice; } // この関数のコードを実行する前にcostsのmodifierが実行される function register() public payable costs(price) { //まず、costsのmodifierでpriceよりもmsg.value(送信者のvalue)が多いことを確認する。 //次に、registeredAddressesにKeyをmsg.sender、valueをtrueに設定 registeredAddresses[msg.sender] = true; } // この関数のコードを実行する前にonlyOwnerのmodifierが実行される function changePrice(uint _price) public onlyOwner { //まず、onlyOwnerのmodifierでコントラクトを実行したアドレスとownerが等しいか確認する //次に、registeredAddressesにKeyをmsg.sender、valueをtrueに設定 price = _price; } } |
このコードでは、下記のような仕組みでmodifierを使って関数実行前に前提条件を確認しています。
register関数:costsのmodifierでpriceよりもmsg.value(送信者のvalue)が多いことを確認してから実行する関数
changePrice関数:onlyOwnerのmodifierでコントラクトを実行したアドレスとownerが等しいか確認してから実行する関数
最後に
今回紹介したSolidityの仕様やコードをRemix IDEやHardhatで実際に実行やテストをして確認してみましょう。
実際に動かしたり、テストすることで理解が深まるかと思います。
hardhatのインストール手順
HardhatでスマートコントラクトのDeploy手順