day10. Solidity基本文法 – 関数・修飾子 – 

プログラミングにおいて、特定の処理をまとめたコードの塊のことを関数と呼びます。プログラム内で何度も呼び出して使うなど、関数を使うことによってコードの再利用性や保守性を高め、効率的なプログラミングを実現することができます。

プログラミングにおいて、特定の処理をまとめたコードの塊のことを関数と呼びます。プログラム内で何度も呼び出して使うなど、関数を使うことによってコードの再利用性や保守性を高め、効率的なプログラミングを実現することができます。

TOC

関数

関数はスマートコントラクト内の特定の動作や処理を実行するためのブロックです。
関数は次のように定義されます。引数(インプット)の値に何かしらの処理を行い、戻り値(アウトプット)を返す、というものです。
また、詳細は後述しますが、修飾子を付与することによって、どういう特徴を持つ関数であるかを明示することができます。

Solidity
function 関数名(引数) 修飾子 returns (戻り値の型) {
    <処理>
    ...
    return 戻り値;
}

実際の関数の例は、次のようなものになります。addressToPersonday9でも出てきた変数で、addressPerson型の変数を紐付けるマッピングです。ここでは、戻り値として、uint256型のbalance(残高)を返しています。ここで定義されている、publicおよびviewはそれぞれ関数に特徴をもたせる修飾子です。

Solidity
contract PersonStorage {
  ...
  function getBalanceOf(address userAddress) public view returns (uint256){
    uint256 balance = addressToPerson[userAddress].balance;
    return balance;
  }
  ...
}

修飾子

修飾子とは、関数や変数などの要素に対して追加の機能や振る舞いを提供するための記述です。
ここでは、関数もしくは変数に使う修飾子を列挙して、説明します。

可視性修飾子

可視性修飾子は関数や変数がどの範囲でアクセス可能かを制御するためのものです。

  • public:コントラクトの内部からもコントラクトの外部(他のコントラクトやRemixのGUI等)からもアクセス可能です。
  • private:関数や変数が定義されているコントラクト内からしかアクセスすることができません。
  • internal:関数や変数が定義されたコントラクトそのものかそこから派生したコントラクトからのみアクセス可能です。
  • external:外部からの呼び出し専用で、コントラクトの外部からのみアクセス可能です。

前述の関数で例示したgetBalanceOf関数は、public修飾子が付与されているので、コントラクトの外部から呼び出すことができます。例えば、Remixで関数の実行結果をGUIから確認したい場合には、publicを使います。
Remixでの実行例は下記のとおりですが、引数にaddressの値を指定し、実行すると、残高として1ETHが返っています。

前述の関数で例示したgetBalanceOf関数は、public修飾子が付与されているので、コントラクトの外部から呼び出すことができます。例えば、Remixで関数の実行結果をGUIから確認したい場合には、publicを使います。
Remixでの実行例:getBalanceOfは、publicが付与されているので、外部から呼び出すことができます。

状態修飾子

状態修飾子も修飾子の一種で、関数がスマートコントラクトの状態に対してどのような影響を与えるかを指定します(変数ではなく、関数に対しての修飾子ですが、payableについては、address型の修飾子として使う場合もあります)。

  • view:関数がスマートコントラクトの状態を変更しない、つまりスマートコントラクト内で定義された変数の値を変更しないことを示します。状態を変更しないことによって、ガスコストが低くなる傾向があります。
  • pureview同様に関数がスマートコントラクトの状態を変更しないことに加えて、関数の外部のデータ(スマートコントラクト内の変数等)を参照できないことを示します。純粋な数学的演算や計算に使われます。状態を変更しないことによって、ガスコストが低くなる傾向があります。
  • payable:関数がEtherの受け取りを許可することを示します。Etherの送金、受け取りなど通貨のやり取りを伴う操作については、明示的にpayableを指定する必要があります。

前述の例のgetBalanceOfは、スマートコントラクト内の変数を参照はしますが、変更は何もしないので、viewが適切になります。

payableの例を次に示します。この例では、deposit(入金)関数の修飾子としてpayableが付いています。この関数をコールした人(msg.sender)とその送金額(msg.value)をbalances(残高)というマッピング型の変数に記録する、という処理を実施しています。

Solidity
mapping(address => uint) balances;

function deposit() payable external {
    balances[msg.sender] += msg.value;
}

msg.sendermsg.valueは特殊な変数で、次のような意味を持ちます。

  • msg.senderdeposit関数を呼んだ人またはコントラクトのアドレス
  • msg.valuedeposit関数を呼ぶ際に送金されたEtherの金額

Remixでdeposit関数を呼んだ場合の例は次のようになります。Valueに送金額を入力し、depositのボタンを押すと外部(Remix)から関数を呼ぶことができます。関数が呼ばれるとdeposit関数をコールするトランザクションが発行され、トランザクションには、msg.senderとして、0x5B3…のアドレス、msg.valueとして、1000000000000000000Wei(1ETH)の数字が含まれています。

Remixでdeposit関数を呼んだ場合の例。Valueに送金額を入力し、depositのボタンを押すと呼ぶことができます。

関数修飾子

modifier(関数修飾子)は、関数に動作や振る舞いを付加するために使われます。
関数間で共通に利用される処理を定義することが可能で、これによって、該当の処理の再利用性を高めることができます。

次の例では、onlyOwnerというmodifierが定義されており、関数changeOwneronlyOwnerが修飾されています。これによって、changeOwnerの処理の冒頭で、この関数を呼んだ人が現在のownerであるかのチェックが行われます。ownerと異なる場合には、エラーメッセージが表示され、関数は実行されません(トランザクションが実行されずに戻されることをrevertと呼びます)。ownerと同じ場合には、引数で指定されたアドレスが新しいownerになります。

Solidity
contract PersonStorage {
  address public owner = 0x551af3f6A226a62BCb27f08B42401bd5629f2E44;
  ...
  modifier onlyOwner() {
      // エラーは、"コントラクト所有者のみが実行可能な関数です。"の意味
      require(msg.sender == owner, "Only contract owner can call this function");
      _; // プレースホルダー(関数の実行箇所)
  }

  function changeOwner(address newOwner) public onlyOwner {
      owner = newOwner;
  }
}

その他の修飾子

定数とは、常に一定の値を示す変数のことですが、定数を定義するための修飾子として、constantimmutableの2つがあります。

  • constant: 値が一度設定されたら変更することができず、実行時は常に同じ値を持ちます。変数を定義する際に、値も合わせてセットする必要があります。
  • immutable: constantと同様に変更できない定数ですが、値のセットは変数を定義する際か、もしくは、コンストラクターと呼ばれるコントラクトの初期化処理の際に呼ばれる特殊な関数内、のいづれかで実行する必要があります。

次の例では、FEE(手数料)というconstant変数およびi_owner(所有者)というimmutable変数が定義されています。FEEとして、0.1ETHを想定し、これは変更することはできません。i_ownerは所有者のアドレスを設定するためのものですが、変数を定義する時ではなく、PersonStorageコントラクトが初期化(デプロイ)される際に一度だけconstructor関数が呼ばれ、その中で、このコントラクトをデプロイした人のアドレスがセットされます。

慣習の一つとして、constant変数は大文字で定義され、immutable変数はi_を頭につけて定義されることがあります。

Solidity
contract PersonStorage {
  uint256 public constant FEE = 1e17; // 0.1ETH
  address public immutable i_owner;
  ...
  constructor() {
    i_owner = msg.sender;
  }
}

ご意見をお聞かせください!

web3チュートリアルシリーズについてのご意見を是非お聞かせください。

この記事、または、web3チュートリアル全体について、是非、あなたのご意見をお聞かせください。
アンケートはこちらからご回答いただけます。

無料相談承ります

ITの専門家が無料相談を受け付けます。web3以外のテーマでもOKです。

オンラインでの無料相談を承っています。ご希望の方は、お問い合わせフォームよりご連絡ください。
ITの専門家があなたのご質問にお答えいたします。

Let's share this post !

Author of this article

After joining IBM in 2004, the author gained extensive experience in developing and maintaining distributed systems, primarily web-based, as an engineer and PM. Later, he founded his own company, designing and developing mobile applications and backend services. He is currently leading a Tech team at a venture company specializing in robo-advisory.

Comments

To comment

CAPTCHA


TOC