Q语言——环境变量

前言

Q语言会话中创建的所有实体的集合我们称为工作区。这不仅包括显式创建的变量,还包括辅助项,如枚举、打开的各类句柄、从存储映射的表和其他内部结构。

q)a:44
q)h:hopen `::5042
q)f:{x*x}
q)\l E:\data\t
q)\l E:/data/t
q)\l /db
q)get `. /查询工作区中有哪些实体,返回的是字典的形式
a | 44
h | 64i
f | {x*x}
E:\data\t| +`c1`c2`c3!(`a`b`c;10 20 30;1.1 2.2 3.3)
t | +`c1`c2`c3!(`a`b`c;10 20 30;1.1 2.2 3.3)
sym | `aapl`ibm`goog
trades | +`dt`tm`sym`qty`px!`:trades/

与其他编程环境一样,Q语言也具有名称冲突的可能性 - 例如,当两个不同的脚本定义同名变量时。因为Q没有宽泛的作用域,并且局部变量严格限定为定义它们的函数,所以局部变量的名称冲突不是问题,但全局变量可能就存在问题。假设您加载了一个创建全局的脚本foobar。然后加载另一个也创建的脚本foobar。结果就是第二个脚本覆盖第一个脚本中分配的值。

这是程序的两个部分争用同一资源的条件的最简单示例。引入并发时事情变得更加复杂,在这种情况下,争用可能导致所谓的竞争条件。幸运的是,q默认是单线程的,并且线程的实现不支持变异全局变量。尽管如此,简单的名称冲突仍然是一个真正的问题。

一、命名空间

针对前面提到的问题,目前Q给的解决方案是制定命名空间——在名称上分层结构化的思想。这种结构思想可以参考我们的文件夹路径,比如:E:\db\trades,你在不同的文件夹下肯定可以创建相同名称的文件。

在Q语言中,我们使用“.”号来创建结构化的变量。“.”用作分隔符。在Q中,容器称为上下文(我觉得理解为环境更好)。例如,.jab.x表示环境中变量x包含在环境jab中。环境jab具有符号名称.jab,其变量的绝对名称为.jab.x。

我们会经常提到什么根目录,在根目录下我们可以创建各种文件或者文件夹,那在Q的命令空间中,也存在一个根环境,在根环境下我们可以创建各种变量或者子环境,根环境就是一个“.”号。

二、环境

Q的命名空间其实是通过字典来实现的,环境就是一个字典(key—value),key就是对应的环境中变量的名称,value就是变量所对应的内容。下面的都是根环境下的各类实体。

q)get `. /查询工作区中有哪些实体,返回的是字典的形式
a | 44
h | 64i
f | {x*x}
E:\data\t| +`c1`c2`c3!(`a`b`c;10 20 30;1.1 2.2 3.3)
t | +`c1`c2`c3!(`a`b`c;10 20 30;1.1 2.2 3.3)
sym | `aapl`ibm`goog
trades | +`dt`tm`sym`qty`px!`:trades/
q).bar.a:43
q).bar.double:{2*x}
q)get `.bar /查询bar环境下的各类变量
 | ::
a | 43
double| {2*x}

Kx保留单个字母的所有根名称空间.kx,供其自己使用。值得注意的是,大多数未使用C语言编写的Q内置函数都存在于.q命名空间中。Kx的包括命名空间.h,.j,.o,.q,.u,.z和.Q。

三、环境的创建

当开始一个全新的Q会话时,创建的所有全局变量都存在于根环境中。如:

q)answer:42
q)calculate:{(x*x)+(-1*x)+1}
 创建环境变量也非常简单,如:
q).foo.a:42 / 环境foo创建
q).foo.double:{2*x}  / 已经存在的环境foo直接使用
q).bar.a:43  / 新的环境bar创建
q).bar.double:{2*x}  / 已经存在的环境bar直接使用
q)key ` /查询存在哪些环境
`q`Q`h`j`o`foo`bar /返回系统中已经创建的环境
q).apl.core.calc.array.fill0:{0.0^x}
q)key `
`q`Q`h`j`o`bar`foo`apl /key查询环境一次只能查询一级
q)key `.apl /这里查询环境apl的下一级
``core
q)key `.apl.core /继续下一级查询
``calc

四、环境变量字典

前面我们介绍过,变量在环境中都是以字典的形式保存的。字典的key是它包含的变量的符号名称; value是与变量关联的当前值。当我们开始一个全新的会话窗口时,我们的环境字典是一个空值。

q)get `. 
q)-3! get `. /我们使用-3!关键字来显示get `.的内容
"(`symbol$())!()" /返回的结果是一个空字典

我们开始创建变量的时候,系统就会将对应的信息添加到我们的环境变量字典中。

q)a:42
q)double:{x*x}
q)get `.
a | 42
double| {x*x}

当我们开始创建多级的环境变量的时候,我们发现在根字典中并不包含子变量。

q).jab.wrong:43 /创建多级环境的变量
q)get `. /在根环境变量字典中并不会记录子变量的信息
a | 42
double| {x*x}
q)get `.jab /查询子环境的变量方式
 | ::
wrong| 43

我们也可以通过前面介绍的字典查询的方式来检索变量内容

q)`.[`a]
42
q)`.jab[`wrong]
43
修改全局变量也有特殊的方式:
q)a
42
q){a:43; `.[`a]}[] /我们发现在函数中我们并不能修改全局变量a的值
42
q){`a set 1+ get `a}[] /但是我们可以通过get和set的方式来修改我们的全局变量
`a
q)a
43

五、环境变量删除

我们已经看到环境字典是一个将当前环境的实体名称映射到它们的值。这意味着从环境中删除实体,我们可以直接从环境字典中删除它。但这是不好的做法,因为它使用底层实现,实际表达式容易输入错误。Q为此提供了删除模板的特殊重载。

q)a:42
q).jab.wrong:43
q)get `.
a | 42
double| {x*x}
q)get `.jab
 | ::
wrong| 43
q)delete from `. /删除根环境中所有变量值
`.
q)a /这时我们发现全局变量a已经不存在了
'a
q)get `.
q)delete wrong from `.jab /删除子环境中的变量值
`.jab
q)get `.jab
| ::
q)\v  /通过\v命令可以查看环境中有哪些变量
`symbol$() /因为已经删除完了,所以就返回一个空列表
q)\v .jab
`symbol$()

六、保存与加载环境变量

由于环境中的变量是以字典的形式保存的,因此可以将其及其所有内容作为序列化。

q)a:42
q)double:{2*x}
q)calculate:{(x*x)+(-1*x)+1}
q)c:(1 2 3)
q)get `.
a | 42
double | {2*x}
calculate| {(x*x)+(-1*x)+1}
c | 1 2 3
q)`:/data/root set get `. /将当前环境中的所有变量序列化到本地磁盘
`:/data/root
q)delete from `. /然后删除当前根环境中的所有变量
`.
q)get `. /跟环境中的所有变量删除成功
q)`. set get `:/data/root /将序列化到本地的环境变量导入到内存中
`.
q)get `. /这时我们可以看到之前删除的变量又回来了
a | 42
double | {2*x}
calculate| {(x*x)+(-1*x)+1}
c | 1 2 3

七、环境切换

我们经常会切换不同的文件夹操作不同的文件,Linux中我们也会经常使用cd命令来切换不同的环境目录,CMD中我也会经常使用cd命令来切换不同的目录。在Q中也一样,我们使用\d命令来切换不同的环境目录。

q).jab.util.counter:0 /创建一个多级的变量counter
q).jab.util.incrctr:{[] `.jab.util.counter set 1+get `.jab.util.counter} 
/创建一个多级环境的函数incrctr
q).jab.util.incrctr[] /运行incrctr函数,注意这里需要给绝对名称.jab.util.incrctr,
否则就会报错,因为默认根环境运行,根环境未定义incrctr函数
`.jab.util.counter
q)\d .jab /通过\d命令切换环境
q.jab)util.incrctr[] /运行jab环境中的util环境下的incrctr函数
`.jab.util.counter
q.jab)util.counter /因为运行了两次,所以变量counter最后的结果为2
2
q.jab)\d . /切换到根环境中
q)util.counter /此时查询变量counter的值就需要给定绝对的环境
'util.counter
q).jab.util.counter
2

接下来我们讨论相同的变量名称在不同的环境中的一个应用。

q)state:`China  /全局变量state
q).jab.f1:{[] state} /这时我们在根环境中创建一个多级环境的变量f1函数,
调用了state变量,则默认调用当前环境(根环境)中的state变量
q)\d .jab /切换到jab环境中
q.jab)state:`UK /在jab环境中创建一个与根环境下相同名称的state变量
q.jab)f2:{[] state} /这时创建一个f2函数,也调用了state变量,也是调用的
当前环境中(jab环境)的state变量的值。
q.jab)\d . /切换到根环境
q).jab.f1[] /调用jab环境中的f1函数
`China
q).jab.f2[] /调用jab环境中的f2函数
`UK
/可以发现两个函数虽然都在jab环境下,但是由于定义两个函数所在的目录不同,
因此最终调用的state的值是不同的
q).jab.f1
{[] state}
q).jab.f2
{[] state}

为了使命名空间中的变量将有效运行,官方建议遵循以下建议:

1)使用任意深度的命名空间来创建全局变量(函数)的分层组织。
2)将相关函数和它们所需的任何变量一起保存在层次结构中的适当环境中,并带有描述性名称。
4)按照惯例,Q名称空间都是小写的。
5)使用绝对环境从根环境定义所有全局实体。
6)始终使用绝对环境来调用全局实体。

你可能感兴趣的:(Q语言——环境变量)