多语境的操作
根据前一章的说法,代码运行时会从USER 语境中查询单字的定义,其实不完全是这样的。
代码中的单字是可以从不同语境中查询定义的。为了证明这一点,这里再做一个实验。
步骤一,我先通过context 函数,分别为苹果(Apple)与谷歌(Google)建立它们各自专
用的语境。苹果的语境叫做Apple,里面只有一个单字OS,定义为"iOS"。谷歌的语境叫做
Google,里面只有一个单字OS,定义为"Android"(安卓)。意思是这两家公司谈到OS(操
作系统)的时候,指的是不同的东西,Apple 说的OS 是iOS,Google 则是指Android。
步骤二,我建立两个代码方块,分别叫做Apple-fan(果粉)与Google-fan(谷粉),内
容都是[print OS]。
步骤三是重点:通过bind 函数,让Apple-fan 采用Apple 语境,让Google-fan 采用
Google 语境。
步骤四,我通过insert 函数,把两段代码串在一起(把Apple-fan 与Google-fan 的内
容都放到code 中)。我在步骤五证实合并正确。步骤六,执行这段代码,发现显示出来的结
果居然不一致,说明一段代码可以采用不同的语境。
为了加深印象,请看下面的慢动作分解。
Apple: context [ OS: "iOS" ]
Google: context [ OS: "Android" ]
为了方便解说,我假设上述两个命令行是一起执行的(就像是一个命令行)。
执行上述代码前,REBOL 解释器会在USER 语境内准备好Apple、context、OS、Google
这四个单字, 并从LIB 语境中将context 定义复制过来(LIB 语境中没有Apple、OS、
Google,所以无法复制这三者的定义)。执行此代码后,会产生两个新的语境,分别成为
USER 语境中Apple 单字与Google 单字的定义。最后USER 语境中剩下OS 的定义是特殊
值unset(表示尚未设定)。
Apple-fan: [ print OS ]
Google-fan: [ print OS ]
为了方便解说,我假设上述两个命令行是一起执行的(就像是一个命令行)。
执行上述代码前,REBOL 解释器会在USER 语境内新增Apple-fan、print、Googlefan
这三个单字,并从LIB 语境中将print 定义复制过来(LIB 语境中没有Apple-fan 与
Google-fan 的定义)。执行后,Apple-fan 与Google-fan 的定义都是代码方块,内容都
是[print OS]。print 与OS 被标上红色三角,表示它们都是采用USER 语境(红色的表)
的单字定义。
bind Apple-fan Apple
bind Google-fan Google
为了方便解说,我假设上述两个命令行是一起执行的(就像是一个命令行)。
执行上述代码前,REBOL 解释器会在USER 语境内新增bind,并从LIB 语境中将bind 定
义复制过来。执行此代码后,Apple-fan 内的代码要被绑定到Apple 语境,但Apple 语境
中的单字只有OS,没有print,所以只有OS 被绑定到Apple 语境,print 维持原来的绑
定(USER 语境)。同理,Google-fan 内的代码只有OS 被绑定到Google 语境,print 维
持原来的绑定(USER 语境)。
code: []
insert code Apple-fan
insert code Google-fan
为了方便解说,我假设上述三个命令行是一起执行的(就像是一个命令行)。
执行这段代码前,REBOL 解释器会在USER 语境内新增code 与insert,并从LIB 语境中
将insert 定义复制过来。执行此代码后,code 内容指向一个新的代码方块,方块内有四个
单字,复制自Apple-fan 与Google-fan。注意区分这里的四个单字分别采用哪些语境。由
于Google-fan 的代码较晚插入方块头部(insert 是插入头部的意思),所以第一个OS 其
实是来自Google-fan 的。
code
do code
为了方便解说,我假设上述两个命令行是一起执行的(就像是一个命令行)。
执行这段代码前,REBOL 解释器会在USER 语境内新增do,并从LIB 语境中将do 的定义
复制过来。执行此代码后,屏幕上会依次打印出Google 语境的OS 值("Android")与
Apple 语境的OS 值("iOS")。
接续前面的例子,Google 语境与Apple 语境都有OS。这时如果我们直接在交互环境中输入
OS,想取得OS 的值,却得到报错,告诉我们OS 没有值。USER 语境中确实有OS,只是其定
义是特殊值unset(未设),相当于没有值。接着我们把OS 设置为"Windows",以后我们取
得的OS 就会是"Windows"。
要如何获取Apple 或Google 内的OS ?我们可以通过加入路径(path)来实现:在OS 前面
冠上它的来源语境,并用斜杠隔开,写成Apple/OS 与Google/OS。
路径不限定两层,可以有多层次。例如,system/options/home 就是三层的路径,可以取
得REBOL 主目录。
再来看另一个例子,PI(圆周率)的值原本是3.14159265358979,我们把它改为简单一点
的值3.14。不用担心这个比较精确的值就因此消失了,你改变的只是USER 语境中的PI 复
制版本,原本的PI 还在LIB 语境中,通过LIB/PI 路径的写法就可以得到原本的值了。
写代码时,我们常需要让一些值聚在一起,例如,记录同一个人的信息就放在一起["Tony"
1983-12-21]。为了清楚表达这些数据的意义,我们通常会在前面加上字段名称,变成
[name: "Tony" birthday: 1983-12-21]。我们常会把像这样的数据包装成对象(object)。
对象的写法如下所示:
customer1: object [name: "Tony" birthday: 1983-12-21]
customer2: object [name: "John" birthday: 1978-1-15]
这里有两个对象,它们的数据分别被隔开,不用担心"John" 会覆盖"Tony",因为它们的
name 是在不同的对象内。
这是不是感觉很像语境?没错! REBOL 其实就是用处理对象的方式来处理语境。语境和对象
在REBOL 语言中是不区分的,作用完全一样。一般来说,语境内放的单字比较多;对象内放
置的单字(字段)比较少。语境内的值不固定,变化很多;对象内的值则相对固定,就像是数
据库的字段一样。语境内函数占大多数,而对象内数据居多。
程序执行的过程会需要经常查询语境,从中找出单字对应的定义,才知道要如何执行。
我们证明过,单字的定义可以来自不同的语境。甚至即使同样的值,真正执行时也可以有不同
的意义(受到该值前面的函数控制),每个值都可能会影响后续值的意义。
REBOL 是Relative Expression Based Object Language 的缩写,意思就是此语言让你能够根据上
下文(语境)做出不同的表达。同样的一个字,在不同的上下文中可以有不同的定义与效果。
与上下文有关,更容易理解,代码更容易阅读,更简短。
这是一门神奇的语言,威力强大,既神奇又先进。
本文节选自《编程ING:人人都能学会程序设计》一书蔡学镛 著电子工业出版社出版图书详细信息: