深入理解aardio的名字空间机制
名字空间的概念与作用
在aardio编程中,名字空间(namespace)主要用于解决标识符命名冲突的问题。举一个生活中的例子:如果有两个叫"李四"的人,一个是上海地区的,一个是深圳地区的,为了区分他们,可以在前面加上地区前缀,比如上海.李四和深圳.李四,这样就能准确识别具体是哪个人了。
默认名字空间详解
aardio程序启动时,会自动创建一个名为global的默认名字空间。所有在文件中直接定义的变量和函数都会被放置在这个默认名字空间里。
使用import语句可以将其他名字空间导入到global或其他名字空间中,使其在该作用域内可用。这就像aardio为每个程序提供了一个初始容器(global),程序员可以在其中编写代码,也可以放置其他容器,而这些容器内部又可以包含更多的容器。
从本质上讲,global本身就是一个table对象,其中定义的函数和导入的名字空间都作为global的成员,可以通过表的方式进行访问和操作。
示例代码一:访问global成员
import win;
global["win"].msgbox(type(global))
global.win.msgbox("hello world")
示例代码二:全局函数调用
import win;
showMessage = function(){
win.msgbox("showMessage call")
}
global["showMessage"]()
需要特别注意:使用var关键字定义的局部变量不会添加到对应的名字空间中。
示例代码三:局部变量测试
import win;
var showMessage = function(){
win.msgbox("showMessage call")
}
global["showMessage"] // 返回null
动态导入机制
可以通过global.import函数动态导入以字符串形式指定的名字空间,这在某些需要运行时决定导入模块的场景中非常有用。
global.import("win")
global["win"].msgbox("动态导入成功")
名字空间外的标识符
在lib目录下创建一个名为testlib.aardio文件,内容如下:
greet = function(){
win.msgbox("aaaaaaaaaaa")
}
namespace testlib{
}
上面的代码将greet函数定义在namespace之外,那么它属于哪个名字空间呢?答案是global。
但是,如果不导入testlib名字空间,将无法直接使用greet函数:
import win;
greet() // 报错:找不到该函数
只有导入testlib后才能正常使用:
import win;
import testlib;
greet()
经过测试发现,当执行import xxx时,aardio会先查找是否存在名称为xxx的文件或目录,然后将该模块中定义的部分全局变量(不使用var修饰的)、全局函数以及子名字空间添加到global中。
如果需要在模块内部访问global中定义的标识符,可以使用..前缀,或者使用global["标识符名"]的方式。
示例:在模块内访问global成员
import win;
namespace testlib{
..win.msgbox("在模块内访问global成员")
}
由于win已经被导入到global中,导入testlib后也可以直接使用win:
import testlib;
win.msgbox("aaaaaa")
不过建议将import语句放在名字空间外部,这样可以避免混淆:
import win;
import testlib;
win.msgbox("多次导入不会重复加载")
在namespace内部导入的名字空间也会自动同步到global中。例如testlib中的代码如下:
namespace testlib{
import win;
win.msgbox("testlib内部导入")
}
即使在testlib内部导入win,外部代码仍然可以直接使用win。
名字空间的底层实现
实际上,aardio中的名字空间就是通过table实现的。导入一个名字空间,相当于往table中添加了一个键值对,键是名字空间的名称,值则是另一个table对象。
可以通过以下方式验证:导入一个名字空间后,删除对应的键,观察该名字空间是否还能继续使用。
import win;
global["win"] = null
win.msgbox("aaaaaaaa") // 报错,win已经是null
self关键字的使用
self代表当前所在的名字空间。在global作用域下,self === global成立。它的主要用途是在需要通过字符串动态调用名字空间内的函数时使用,例如self["functionName"]()。
