電卓の関数で整数を使用する

このチュートリアルでは、基本的な算術演算を実行するためのいくつかのパブリックエントリーポイント関数を持つ単一の Actor を作成するシンプルな電卓プログラムを作成します。

このチュートリアルでは、Actor は Calc という名前にしました。 このプログラムは、電卓操作の現在の結果を表す整数を格納する cell 変数を使用します。

このプログラムは、下記の関数呼び出しをサポートします。

  • add 関数呼び出しは、入力を受け取り、加算を行います。

  • sub 関数呼び出しは、入力を受け取り、減算を行います。

  • mul 関数呼び出しは、入力を受け取り、乗算を行います。

  • div 関数呼び出しは、入力を受け取り、除算を行います。

  • clearall 関数呼び出しは、以前の操作の結果として保存された cell の値をクリアし、 cell の値をゼロにリセットします。

div 関数には、プログラムがゼロで割ろうとするのを防ぐためのコードも含まれます。

始める前に

このチュートリアルを始める前に、以下のことを確認してください。

  • ダウンロードとインストール に記載されている DFINITY Canister SDK パッケージをダウンロードしてインストールしていること

  • ローカルコンピュータ上のすべての Canister 実行環境を止めていること

このチュートリアルの所要時間は 20 分程度です。

新しいプロジェクトを作成する

このチュートリアル用に新しいプロジェクトを作成するには

  1. ローカルコンピュータ上でターミナルシェルを、まだ開いていなければ開きます。

  2. 別のフォルダを利用しているなら、Internet Computer プロジェクトで使うフォルダに移動します。

  3. 以下のコマンドを実行して、新しいプロジェクトを作成します。

    dfx new calc
  4. 以下のコマンドを実行して、プロジェクトディレクトリに移動します。

    cd calc

デフォルト設定を変更する

このチュートリアルでは、デフォルトの dfx.json 設定ファイルを変更して、そのメインプログラムにもっと具体的な名前を使いましょう。

デフォルトの設定ファイル dfx.json を変更するには

  1. 設定ファイル dfx.json をテキストエディターで開きます。

  2. キー設定の main をデフォルトのプログラム名 main.mo から calc_main.mo に変更します。

    例えば、下記です。

    "main": "src/calc/calc_main.mo",

    このチュートリアルでは、ソースファイルの名前を main.mo から calc_main.mo に変更し、設定ファイル dfx.json の設定でコンパイルされるソースファイルを決める方法を簡単に説明します。

    より複雑な Dapp では、単一のプログラムファイル main ではなく、複数のソースファイルがあるかもしれません。 より複雑なアプリケーションでは、複数のソースファイル間で特定の依存関係が発生することがあり、その場合は設定ファイル dfx.json 内の設定を使って管理する必要があります。 複数の Canister とプログラムが dfx.json ファイルに定義されているようなシナリオでは、複数のファイルに main.mo という名前を付けると、ワークスペースをナビゲートするのがより難しくなるかもしれません。 各プログラムの名前は重要ではありませんが、dfx.json ファイルに設定した名前が、ファイルシステム内のプログラム名と一致することは重要です。

  3. 変更内容を保存し、ファイルを閉じて、続行します。

デフォルトのプログラムを変更する

このチュートリアルでは、デフォルトのプログラムを、基本的な算術演算を行うプログラムに置き換える必要があります。

デフォルトのプログラムを置き換えるには

  1. もし必要であれば、まだプロジェクトディレクトリにいることを確認します。

  2. 以下のコマンドを実行することで、テンプレートの main.mo ファイルをコピーし、calc_main.mo という名前の新しいファイルを作成します。

    cp src/calc/main.mo src/calc/calc_main.mo
  3. テキストエディタで src/calc/calc_main.mo ファイルを開き、既存の内容を削除します。

  4. 下記のサンプルコードをコピーして calc_main.mo ファイルに貼り付けてください。

    // このシングルセル電卓は、各パブリックエントリポイント(add, sub, mul, div)ごとに
    // 1つの電卓命令を定義する。
    
    // シンプルな Calc Actor 作成する。
    actor Calc {
      var cell : Int = 0;
    
      // 足し算、引き算、掛け算、割り算 を行う関数を定義する
      public func add(n:Int) : async Int { cell += n; cell };
      public func sub(n:Int) : async Int { cell -= n; cell };
      public func mul(n:Int) : async Int { cell *= n; cell };
      public func div(n:Int) : async ?Int {
        if ( n == 0 ) {
          return null // null はゼロ除算エラーを意味する
        } else {
          cell /= n; ?cell
        }
      };
    
      // 電卓をクリアしてゼロにリセット
      public func clearall() : async Int {
        if (cell : Int != 0)
          cell -= cell;
        return cell
      };
     };

    このサンプルコードでは、整数 (Int) のデータ型を使用しており、正または負の数を使用できることに気づくかもしれません。 もし、この電卓のコードで正の数しか使えないように関数を制限したい場合は、データ型を変更して自然数 (Nat) のデータしか使えないようにすることも可能です。

  5. 変更内容を保存し、ファイルを閉じて続行します。

ローカル Canister 実行環境を起動する

calc プロジェクトをビルドする前に、開発環境のローカルで動作している Canister 実行環境に接続するか、アクセス可能なサブネットに接続する必要があります。

ローカルでネットワークを起動するには dfx.json ファイルが必要なので、プロジェクトのルートディレクトリにいることを確認する必要があります。 このチュートリアルでは、2つの別々のターミナルシェルを用意し、片方のターミナルでネットワーク操作を開始して確認し、もう片方のターミナルでプロジェクトを管理できるようにする必要があります。

ローカル Canister 実行環境を起動するには

  1. ローカルコンピュータで新しいターミナルウィンドウまたはタブを開きます。

  2. もし必要であれば、プロジェクトのルートディレクトリに移動します。

    • これで、2つのターミナル が開いた状態になります。

    • プロジェクトディレクトリ現在の作業ディレクトリ になっている必要があります。

  3. 下記のコマンドを実行することで、あなたのマシンのローカル Canister 実行環境を起動します。

    dfx start

    ローカルネットワークを起動すると、ターミナルにネットワーク操作に関するメッセージが表示されます。

  4. ネットワーク操作を表示しているターミナルは開いたままにして、新しいプロジェクトを作成した元のターミナルにフォーカスを切り替えます。

Dapp を登録、ビルド、デプロイする

ローカルの Canister 実行環境に接続した後、ローカルで Dapp の登録、ビルド、デプロイを行えます。

Dapp をローカルにデプロイするには

  1. もし必要であれば、まだプロジェクトのルートディレクトリにいることを確認します。

  2. 下記のコマンドを実行することで、Dapp を登録、ビルド、デプロイします。

    dfx deploy

    dfx deploy コマンドの出力は、実行した操作に関する情報を表示します。

キャニスターで電卓の関数を確認する

これで、ローカルの Canister 実行環境に Canister スマートコントラクト としてプログラムがデプロイされました。 dfx canister call コマンドを使用することで、プログラムをテストできます。

デプロイしたプログラムをテストするには

  1. dfx canister call コマンドを使用し、下記のコマンドを実行することで、 calc Canister add 関数を呼び出し、入力引数 10 を渡します。

    dfx canister call calc add '(10)'

    シングルクォーテーションと括弧で囲まれた引数を渡すと、インターフェース記述言語(IDL)がその引数の型をパースするので、引数の型を手動で指定する必要はありません。

    このコマンドが、add 関数により、期待される値が返されることを確認します。 例えば、このプログラムでは、下記のような出力が表示されます。

    (10)
  2. 下記のコマンドを実行することで、mul 関数を呼び出し、入力引数 3 を渡します。

    dfx canister call calc mul '(3)'

    このコマンドが、mul 関数により、期待される値が返されることを確認します。 例えば、このプログラムでは、下記のような出力が表示されます。

    (30)
  3. 下記のコマンドを実行することで、 sub 関数を呼び出し、 number 型の入力引数 5 を渡します。

    dfx canister call calc sub '(5)'

    このコマンドが、sub 関数により、期待される値が返されることを確認します。 例えば、このプログラムでは、下記のような出力が表示されます。

    (25)
  4. 下記のコマンドを実行することで、div 関数を呼び出し、入力引数 5 を渡します。

    dfx canister call calc div '(5)'

    このコマンドが、div 関数により、期待される値を返すことを確認します。 例えば、このプログラムでは、下記のような出力が表示されます。

    (opt 5)

    div+ 関数がオプション(opt)の結果を返していることに気付くかもしれません。 このプログラムでは、div 関数がゼロ除算のエラーの場合に null を返せるようにするために、結果をオプション(opt)にしています。

    このプログラムでは cell 変数が整数なので、負の入力値を指定してその関数を呼び出すこともできます。 例えば、あなたは下記のようなコマンドを実行してもよいです。

    dfx canister call calc mul '(-4)'

    下記を返します。

    (-20)
  5. clearall 関数を呼び出し、cell の値がゼロにリセットされることを確認します。

    dfx canister call calc clearall

    例えば、このプログラムでは、下記のような出力が表示されます。

    (0)

ブラウザー上での関数のテスト

キャニスター・インターフェース記述言語(Candid または IDL と呼ばれることが多い)は、canister スマートコントラクトの署名を指定するための共通言語を提供します。Candid は、異なる言語で書かれていたり、異なるツールでアクセスされる canister スマートコントラクトを扱うための統一された方法を提供します。 例えば、Candid は、基礎となるプログラムが Rust、JavaScript、Motoko のいずれであっても、一貫した表示となります。また、Candid は、dfx コマンドラインインターフェイスや Network Nervous System Dapp などの異なるツールが、サービスに対する共通の記述を共有できるようにします。

Actor の型注釈に基づいて、Candid はテストやデバッグのために canister の関数を呼び出すことができる Web インターフェースも提供しています。

dfx deploy または dfx canister install コマンドを使用してプロジェクトをローカルの canister 実行環境にデプロイした後、ブラウザで Candid インターフェイスのエンドポイントにアクセスできます。 この Web インターフェイス(Candid UI)は、サービスの説明を決められた形式で表現しており、フロントエンドのコードを書くことなく、関数をすばやく表示してテストしたり、さまざまなデータタイプを入力して実験したりすることができます。

Candid の Web インターフェースを使って canister の関数をテストするには、以下のようにします:

  1. 現在のプロジェクトに関連する Candid UI の canister の識別子を、dfx canister id __Candid_UI コマンドを使って見つけます。

    dfx canister id __Candid_UI

    このコマンドは、Candid UIの canister 識別子を以下のような出力で表示します。

    r7inp-6aaaa-aaaaa-aaabq-cai
  2. Candid UI の canister 識別子をクリップボードで使用できるようにコピーします。

  3. ローカルの canister 実行環境を停止した場合は、以下のコマンドを実行してローカルで再起動します。

    dfx start --background
  4. ブラウザを開き、設定ファイルである dfx.json で指定されたアドレスとポート番号に移動します。

    デフォルトでは、ローカルの canister 実行環境は、127.0.0.1:8000 のアドレスとポート番号にバインドされます。

  5. 必要な canisterId パラメータと、dfx canister id __Candid_UI コマンドで返される Candid UI の canister 識別子を URL に追加します。

    例えば、完全な URL は以下のようになりますが、CANDID-UI-CANISTER-IDENTIFIERdfx canister id __Candid_UI コマンドで返された値になります。

    http://127.0.0.1:8000/?canisterId=<CANDID-UI-CANISTER-IDENTIFIER>

    例えば、上記の Candid UI の canister 識別子の例では、以下のようになります。

    http://127.0.0.1:8000/?canisterId=r7inp-6aaaa-aaaaa-aaabq-cai

    ブラウザには、canister の識別子を指定するか、Candid の説明( .did )ファイルを選択するためのフォームが表示されます。 このフィールドは、対話したい canister の識別子を参照することに注意してください(最後のステップで使用した Candid UI の canister 識別子とは異なります)。

  6. テストしたい canister の識別子を「 Provide a canister ID 」フィールドに指定し、「 Go 」をクリックしてサービスの説明を表示します。

    使用する canister の識別子がわからない場合は、dfx canister id コマンドを実行して、特定の canister 名の識別子を調べることができます。 例えば、my_counter という名前の canister の識別子を得るには、次のようにします:

    dfx canister id my_counter
  7. Dappで定義されている関数の呼び出しと型のリストを確認します。

  8. 関数に合った型の値を入力するか、「 Random 」をクリックして値を生成し、「 Call 」または「 Query 」をクリックして結果を確認します。

    なお、データ型によっては、Candid インターフェースに、関数をテストするための追加の設定が表示される場合があります。 例えば、関数が配列を取る場合は、値を入力する前に配列のアイテム数を指定する必要があるかもしれません。

+ Calculator functions

ローカルの Canister 実行環境を停止する

Dapp の実体験が終わったら、バックグラウンドで実行し続けないように、ローカルの Canister 実行環境を停止できます。

ローカルの Canister 実行環境を停止するには

  1. 操作が表示されているターミナルで、Control-C を押して処理を中断します。

  2. 下記のコマンドを実行することで、ローカルの Canister 実行環境を停止します。

    dfx stop