Importing from the Motoko base library:

最常见的导入场景之一是本指南中的示例、示例存储库中的Motoko项目以及涉及从Motoko库导入模块的教程中所示的场景。通过从基本库导入模块,可以重用这些模块中定义的值、函数和类型,而不是从头开始编写类似的值、函数和类型。

以下两行从Array和Result模块(Modules)导入函数:

import Array "mo:base/Array"; 
import Result "mo:base/Result";

请注意,导入声明包含mo:前缀以将模块标识为Motoko模块,并且该声明不包含.mo文件类型扩展名。

Importing local files:

用Motoko编写程序的另一种常见方法是将源代码分成不同的模块。例如,您可以将应用程序设计为使用以下模型:

  • a main.mo file to contain the actor and functions that change state.
  • a types.mo file for all of your custom type definitions.
  • a utils.mo file for functions that do work outside of the actor.

在这种情况下,您可以将所有三个文件放在同一目录中,并使用本地导入使函数在需要时可用。

例如,main.mo包含以下行以引用同一目录中的模块:

import Types "types"; 
import Utils "utils";

因为这些行从本地项目而不是Motoko库导入模块,所以这些导入声明不使用mo:前缀。

在本例中,types.mo和utils.mo文件与main.mo文件位于同一目录中。再次声明,import不使用.mo文件后缀。

Importing from another package or directory:

也可以从其他包或本地目录以外的目录导入模块。

例如,以下行从定义为依赖项的redraw package导入模块:

import Render "mo:redraw/Render"; 
import Mono5x5 "mo:redraw/glyph/Mono5x5";

您可以使用容器包管理器(the Vessel package manager)或在project dfx.json配置文件中定义项目的依赖项。

在本例中,呈现模块位于redraw package中源代码的默认位置,而Mono5x5模块位于名为glyph的redraw package的子目录中。

Importing actor classes:

虽然模块导入通常用于导入本地函数和值的库,但它们也可以用于导入参与者类。当导入的文件由命名的actor类组成时,导入字段的客户机将看到包含actor类的模块。

此模块有两个组件,均以actor类命名:

  • a type definition, describing the interface of the class, and
  • an asynchronous function, that takes the class parameters as arguments an asynchronously returns a fresh instance of the class.

“类型定义,描述类的接口,以及一个异步函数,将类参数作为参数异步返回类的新实例。”

例如,Motoko actor可以导入并实例化 Actors and async data中描述的Counter类,如下所示:

Counters.mo

actor class Counter(init : Nat) { 
	var count = init; 
	public func inc() : async () { count += 1 }; 
	public func read() : async Nat { count }; 
	public func bump() : async Nat { count += 1; count; }; 
};

结果:func : Nat -> async Counter

CountToTen.mo

import Counters "Counters"; 
import Debug "mo:base/Debug"; 
import Nat "mo:base/Nat"; 
actor CountToTen { 
	public func countToTen() : async () { 
		let C : Counters.Counter = await Counters.Counter(1); 
		while ((await C.read()) < 10) { 
			Debug.print(Nat.toText(await C.read())); 
			await C.inc(); 
		}; 
	}
};
await CountToTen.countToTen()

结果:
1
2
3
4
5
6
7
8
9
() : ()

对Counters.Counter(1)的调用在网络上安装新的计数器。安装是异步的,因此调用者必须等待结果。

类型注释:Counters.Counter在这里是多余的。包含它只是为了说明actor类的类型在需要时可用。

Importing from another canister:

除了上面导入Motoko模块的示例之外,还可以使用canisters:前缀代替mo:前缀从canisters导入函数。

For example, you might have a project that produces the following three canisters:

  • BigMap
  • Connectd
  • LinkedUp

这三个容器在项目的dfx.json配置文件中声明,并通过运行dfx build进行编译。

然后可以使用以下面两行从LinkedUp程序中的BigMap和Connectd容器导入函数:

import BigMap "canister:BigMap"; 
import Connectd "canister:connectd";

导入容器时,请务必注意,导入的容器的类型对应于Motoko actor而不是Motoko模块。这种区别会影响某些数据结构的类型。

对于导入的容器actor,类型是从容器的Candid文件project-name.did文件派生的,而不是从Motoko本身派生的。

从Motoko actor类型到Candid服务类型的转换主要是一对一的,但不完全是一对一的,并且有一些不同的Motoko类型映射到相同的Candid类型。例如,Motoko Nat32和Char类型都作为Candid类型Nat32导出,但是Nat32是作为Motoko Nat32而不是Char规范导入的。

因此,导入的容器函数的类型可能与实现它的原始Motoko代码的类型不同。例如,如果Motoko函数在实现中具有类型shared Nat32->async Char,则其导出的Candid类型将是(Nat32)->(Nat32),但从该Candid类型导入的Motoko类型实际上是正确的,但可能是意外的类型shared Nat32->async Nat32。

这些类型的差异是容器抽象所固有的对Motoko组成层坦诚的结果。(甩锅???

Naming imported modules:

尽管最常见的约定是通过模块名来标识导入的模块,如上面的示例所示,但并不要求您这样做。例如,您可能希望使用不同的名称来避免命名冲突或简化命名方案。

以下示例演示了导入列表库模块时可能使用的不同名称,以避免与from a fictional collections package另一个List库发生冲突。

import List "mo:base/List:"; 
import Sequence "mo:collections/List"; 
import L "mo:base/List";

A Student on the way to full stack of Web3.