多语境的操作
根据前一章的说法,代码运行时会从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 ObjectLanguage 的缩写,意思就是此语言让你能够根据上
下文(语境)做出不同的表达。同样的一个字,在不同的上下文中可以有不同的定义与效果。
与上下文有关,更容易理解,代码更容易阅读,更简短。
这是一门神奇的语言,威力强大,既神奇又先进。
本文节选自《编程ING:人人都能学会程序设计》一书
蔡学镛 著
电子工业出版社出版
图书详细信息:http://blog.csdn.net/broadview2006/article/details/7768124