在计算器函数中使用整数

在本教程中,您将编写一个简单的计算器程序,该程序创建一个具有多个公共入口点函数的单个参与者,以执行基本的算术运算。

在本教程中,actor 被命名为 Calc。 该程序使用 cell 变量来包含一个整数,该整数表示计算器操作的当前结果。

该程序支持以下函数调用:

  • add 函数调用接受输入并执行加法。

  • sub 函数调用接受输入并执行减法。

  • mul 函数调用接受输入并执行乘法。

  • div 函数调用接受输入并执行除法。

  • clearall 函数清除作为先前操作结果存储的`cell` 值,将`cell` 值重置为零。

div 函数还包括防止程序试图除以零的代码。

开始之前

在开始本教程之前,请验证以下内容:

  • 您已按照下载并安装中的说明下载并安装了 {sdk-short-name} 包。

  • 您已停止在本地运行的任何容器执行环境 计算机。

完成本教程大约需要 20 分钟。

创建一个新项目

要为本教程创建一个新项目:

  1. 如果您还没有打开一个终端外壳,请在您的本地计算机上打开一个终端外壳。

  2. 更改为您用于 Internet Computer 项目的文件夹(如果您正在使用一个)。

  3. 通过运行以下命令创建一个新项目:

    dfx new calc
  4. 通过运行以下命令切换到您的项目目录:

    cd calc

修改默认配置

对于本教程,让我们修改默认的“dfx.json”配置文件,为其主程序使用更具体的名称。

修改默认的 dfx.json 配置文件:

  1. 在文本编辑器中打开 +dxf.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 配置文件中的设置来管理这些依赖关系。 在这样的场景中——在你的“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 文件中:

    // This single-cell calculator defines one calculator instruction per
    // public entry point (add, sub, mul, div).
    
    // Create a simple Calc actor.
    actor Calc {
      var cell : Int = 0;
    
      // Define functions to add, subtract, multiply, and divide
      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 indicates div-by-zero error
        } else {
          cell /= n; ?cell
        }
      };
    
      // Clear the calculator and reset to zero
      public func clearall() : async Int {
        if (cell : Int != 0)
          cell -= cell;
        return cell
      };
     };

    您可能会注意到此示例代码使用整数 (Int) 数据类型,使您能够使用正数或负数。 如果您想将此计算器代码中的函数限制为仅使用正数,您可以将数据类型更改为仅允许自然 (Nat) 数据。

  5. 保存更改并关闭文件以继续。

启动本地容器执行环境

在构建 calc 项目之前,您需要连接到在您的开发环境中本地运行的容器执行环境,或者您需要连接到您可以访问的子网。

在本地启动网络需要一个 dfx.json 文件,因此您应该确保您位于项目的根目录中。 对于本教程,您应该有两个独立的终端 shell,以便您可以在一个终端中启动和查看网络操作并在另一个终端中管理您的项目。

启动本地容器执行环境:

  1. 在本地计算机上打开一个新的终端窗口或选项卡。

  2. 如有必要,导航到项目的根目录。

    • 您现在应该打开了两个终端

    • 您应该将 project 目录 作为您的 current 工作目录

  3. 通过运行以下命令在您的机器上启动本地容器执行环境:

    dfx start

    启动本地网络后,终端会显示有关网络操作的消息。

  4. 让显示网络操作的终端保持打开状态,然后将注意力转移到创建新项目的原始终端。

注册、构建和部署 dapp

连接到本地容器执行环境后,您可以在本地注册、构建和部署 dapp。

要在本地部署 dapp:

  1. 如果需要,请检查您是否仍在项目的根目录中。

  2. 通过运行以下命令注册、构建和部署您的 dapp:

    dfx deploy

    dfx deploy 命令输出显示有关它执行的操作的信息。

验证容器上的计算器功能

您现在在本地容器执行环境中部署了一个程序作为*容器智能合约*。 您可以使用 dfx canister call 命令测试程序。

要测试您已部署的程序:

  1. 使用 dfx canister call 命令调用 calc 容器 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 函数返回一个可选结果。 该程序使结果可选,以使 div 函数在除零错误的情况下返回 null

    因为这个程序中的单元格变量是一个整数,你也可以调用它的函数并指定负输入值。 例如,您可以运行以下命令:

    dfx canister call calc mul '(-4)'

    which returns:

    (-20)
  5. 调用 +clearall 函数并验证它是否将 +cell 值重置为零:

    dfx canister call calc clearall

    例如,程序显示类似于以下的输出:

    (0)

在浏览器中测试功能

容器接口描述语言(通常称为 Candid 或更一般地称为 IDL)为指定容器智能合约的签名提供了一种通用语言。 Candid 为您提供了一种统一的方式来与用不同语言编写或使用不同工具访问的容器智能合约进行交互。 例如,无论底层程序是原生 Rust、JavaScript 还是 Motoko,Candid 都能提供一致的服务视图。 Candid 还启用了不同的工具——例如`dfx` 命令行界面和网络神经系统 dapp——来共享服务的通用描述。

基于 actor 的类型签名,Candid 还提供了一个 Web 界面,允许您调用容器函数进行测试和调试。

使用 dfx deploydfx canister install 命令在本地容器执行环境中部署项目后,您可以在浏览器中访问 Candid Web 界面端点。 此 Web 界面 — Candid UI — 以表单形式公开服务描述,使您无需编写任何前端代码即可快速查看和测试功能并尝试输入不同的数据类型。

要使用 Candid Web 界面测试容器功能:

使用 dfx canister id __Candid_UI 命令查找与当前项目关联的 Candid UI 容器标识符。

+

dfx canister id __Candid_UI

+ 该命令显示 Candid UI 的容器标识符,输出类似于以下内容:

+

r7inp-6aaaa-aaaaa-aaabq-cai

+ . 复制 Candid UI 容器标识符,使其在剪贴板中可用。 . 如果您已停止本地容器执行环境,请通过运行以下命令在本地重新启动它:

+

dfx start --background
  1. 打开浏览器并导航到 dfx.json 配置文件中指定的地址和端口号。

    默认情况下,本地容器执行环境绑定到`127.0.0.1:8000`地址和端口号。

  2. 将所需的 canisterId 参数和 dfx canister id __Candid_UI 命令返回的 Candid UI 容器标识符添加到 URL。

    例如,完整的 URL 应该类似于以下内容,但带有由 dfx canister id __Candid_UI 命令返回的`CANDID-UI-CANISTER-IDENTIFIER`:

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

    例如,对于 Candid UI 的示例容器标识符,如上所示,可能如下所示:

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

    然后,浏览器会显示一个表单供您指定容器标识符或选择 Candid 描述 (.did) 文件。 请注意,此字段是指您要与之交互的容器的容器标识符(与我们在上一步中使用的 Candid UI 的容器标识符相反)。

  3. Provide a canister ID 字段中指定要测试的容器的容器标识符,然后单击 Go 以显示服务描述。

    如果您不确定要使用哪个容器标识符,可以运行 dfx canister id 命令来查找特定容器名称的标识符。 例如,要获取名为 my_counter 的容器的容器标识符,您可以使用:

    dfx canister id my_counter
  4. 查看 dapp 中定义的函数调用和类型列表。

  5. 为函数键入适当类型的值或单击 Random 生成值,然后单击 CallQuery 以查看结果。

    请注意,根据数据类型,Candid 界面可能会显示用于测试功能的其他配置设置。 例如,如果一个函数接受一个数组,您可能需要在输入值之前指定数组中的项目数。

    Calculator functions

停止本地容器执行环境

完成 dapp 试验后,您可以停止本地容器执行环境,使其不会继续在后台运行。

要停止本地容器执行环境:

  1. 在显示操作的终端中,按 Control-C 中断该过程。

  2. 通过运行以下命令停止本地容器执行环境:

    dfx stop