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";
Comments NOTHING