Skip to content

Latest commit

 

History

History
196 lines (138 loc) · 9.85 KB

import.md

File metadata and controls

196 lines (138 loc) · 9.85 KB

引用依赖

一个结构清晰的中大型仿真工程离不开引用依赖,不论这些依赖来自于内部或是引用自外部。在 ligral 中,您可以很方便地处理这些依赖关系并且引用到仿真工程中。本文涉及的所有例子均可在/examples/import-logic/下查看。

绝对路径引用

最简单的情况莫过于所有 lig 文件都在同一个文件夹,ligral 提供了两个子句以供使用。例如下面的文件结构:

┬ 根目录
├──── main.lig
└──── library1.lig:
     ┌─────────────────────────────┐
     │let hello = 1;               │
     └─────────────────────────────┘

main.lig中调用hello有两种方法:

# 方法 1
import library1;
hello -> Print;

# 方法 2
using library1;
library1.hello -> Print;

顾名思义,import代表导入,会将文件library1.lig中的所有成员(包括常量、节点和连接关系等等)量导入到当前的命名空间。using代表使用(或引用),即使用library这一命名空间来访问文件library1.lig中的成员。

注意,重复导入或者引用同一个 lig 文件,该文件只会被加载一次。

这个例子中的main.lig被称为入口文件,入口文件所在的目录是工程根目录,是绝对引用的参考目录。也就是说,在此目录下如果还有子文件夹,导入或引用子文件夹中的 lig 文件必须给出相对于工程根目录的路径。例如下面的文件结构:

┬ 根目录
├──── main.lig
└───┬ subfolder:
    └──── sublib1.lig:
         ┌─────────────────────────────┐
         │let world = 1;               │
         └─────────────────────────────┘

同样,根据需要可以使用两种语法来导入或引用该文件,且通过using子句引用的变量需要完整路径引用:

# 方法 1
import subfolder.sublib1;
world -> Print;

# 方法 2
using subfolder.sublib1;
subfolder.sublib1.world -> Print;

相对路径引用

相对路径引用是针对不在工程根目录的文件而言的,因为此时文件所在目录和工程根目录不一致。请看以下文件结构:

┬ 根目录
├──── main.lig
└───┬ subfolder:
    ├──── sublib1.lig
    └──── sublib2.lig:
         ┌─────────────────────────────┐
         │let world = 2;               │
         └─────────────────────────────┘

如果要在sublib1.lig中使用world,以using为例,有绝对引用和相对引用两种方法,绝对引用如下:

using subfolder.sublib2;
subfolder.sublib2.world -> Print;

这么写的前提是入口文件是main.lig。如果入口文件发生变动,这一语句就不能正常执行,因此 ligral 提供了相对应用的方式:

using .sublib2;
sublib2.world -> Print;

sublib2前的.号表明在文件sublib1.lig所在目录搜索sublib2.lig。如果这个目录下仍有文件夹subsubfolder,自然就可以写成.subsubfolder.file

如果要访问上一级目录,就在.号之前继续加.,也就是如果有两个.,表示在上一级目录搜索,如果有三个.,则表示上两级目录。但是一般建议不要超过一级目录进行跨级访问。例如下面的文件结构:

┬ 根目录
├──── main.lig
├───┬ subfolder:
│   └──── sublib1.lig
└───┬ package:
    └──── module1.lig:
         ┌─────────────────────────────┐
         │let ligral = 1;              │
         └─────────────────────────────┘

如果sublib1.lig文件需要引用world,一种方法是通过绝对路径访问,这要求main.lig是入口文件:

using package.module1;
package.module1.ligral -> Print;

如果用相对引用的方式,则可以写:

using ..package.module1;
package.module1.ligral -> Print;

可以看到,标识符前面的两个点是被省略了的,不需要写出上一级文件夹的名字。如果使用import子句,就不会存在这个问题。

包引用

之前的情况都属于文件引用,如果引用了一个文件夹,该文件夹必须是一个包。成为包的充分必要条件就是该文件夹下存在一个index.lig文件,引用该文件夹等效于引用index.lig文件。例如下列文件结构:

┬ 根目录
├──── main.lig
└───┬ package:
    ├──── index.lig:
    │    ┌─────────────────────────────┐
    │    │using .module1;              │
    │    └─────────────────────────────┘
    └──── module1.lig:
         ┌─────────────────────────────┐
         │let ligral = 1;              │
         └─────────────────────────────┘

如果您在main.lig中导入package这个包:

import package;

您将会在当前命名空间看到index.lig中的所有内容。而index.lig中包含module1这一标识符,因此如果您需要使用ligral,应该写:

module1.ligral -> Print;

需要说明的是,在index.lig文件中,您可以选择使用using,也可以使用import,根据实际需要。如果在上面的例子中,index.lig文件里是import .module1;,那么在main.lig中就可以直接调用ligral了。

选择性导入

有的时候一些包或者 lig 文件可能包含很多成员,但实际使用中可能只需要引用其中的部分成员,这时使用using子句可以避免命名污染。但是如果不想通过命名空间的方式来调用对象,可以使用import子句的选择性导入语法。

┬ 根目录
├──── main.lig
└───┬ subfolder:
    └──── sublib4.lig:
         ┌─────────────────────────────┐
         │let world = 4;               │
         │let unused = 0;              │
         └─────────────────────────────┘

如果您只想使用world成员,您可以这么写:

import subfolder.sublib4 : world;
world -> Print;

此时仅有world被导入到当前命名空间,而unused没有,因此不能被访问。如果您需要导入多个成员,可以用逗号分隔。

别名引用

有的时候由于文件层级较多,使用using子句导入往往导致命名空间太长,此时可以使用using子句的别名语法。在上面的例子中,如果使用普通的using子句,需要这么写:

using subfolder.sublib4;
subfolder.sublib4.world -> Print;

如果采用别名语法,把命名空间起名为lib,则可以写:

using subfolder.sublib4 : lib;
lib.world -> Print;

这样可以避免冗长的代码,但是需要注意别名不能和现有的成员冲突。

需要注意的是import子句和using子句虽然都使用了:来扩展语法,但是:的含义是不同的。import子句用:来引出需要导入的成员,using子句用:引出命名空间的别名。不过有一点是相同的:出现:的语句中,:之后的符号会被加载到当前命名空间中,之前的不会。

循环依赖

循环依赖指的是文件 A 依赖于文件 B,同时文件 B 也依赖于文件 A 的情况,这在一般情况下是需要避免的,不是一种良好的编程风格。但这并不意味着循环依赖一定会报错,某些场合很谨慎地使用也是可以解释通过的,通过这种方式您能更深入地了解 ligral 如何处理依赖关系。以下属于进阶内容,感兴趣的话可以深入研究。

┬ 根目录
├──── node1.lig:
│    ┌─────────────────────────────┐
│    │let b = 2;                   │
│    │import .node2;               │
│    │a -> Print;                  │
│    └─────────────────────────────┘
└──── node2.lig:
     ┌─────────────────────────────┐
     │import .node1;               │
     │b -> Print;                  │
     │let a = 1;                   │
     └─────────────────────────────┘

在上面这个例子中,如果程序从node1.lig启动,执行代码的顺序及当前的命名空间如下表所示:

代码 node1 命名空间 node2 命名空间 备注
let b = 2; [b]* -
import .node2 [b] []*
import .node1 [b] [b]* 不会重复加载 node1
b -> Print; [b] [b]* 成功访问到b
let a = 1; [b] [b, a]*
a -> Print; [b, a]* [b, a] 成功访问到a

其中 * 号表示当前的命名空间。