你所知道的并不是你真的知道 —— 程序语言的精髓
2014-10-11 18:30
288 查看
当夜幕已近闭合,沉睡的晚灯张起结界,昏黄中没半点柔情,仿佛在告诉行人:非诚勿扰
夜晚11:11分,注定孤独的时分。Carl倚靠窗台失神了半晌,回过来就顺手拉紧了窗帘。拧开台灯,桌上静静地躺着一本书,是日本人西尾太和的《代码之髓》。他翻开扉页,签上自己的大名,满足地撇撇嘴,开始看起来。
Lisp是这个世界上最精练,最美观的语言
(setq f (let ((x 1)) (lambda (y) (* x y))))
直观上,这个函数f的结果就是(* 1 y),也就是y的值。那么实际调用的结果如何呢?
let ((x 2)) (funcall f 2))
即f(2)的结果是2?实际运行的结果让人大跌眼镜,是4!
Carl揉揉被蹂躏多时的眼球,问自己:为什么是这样,像梦一场?
行文到这里,我们的黑暗主角慢慢展露头角——作用域(Scope)。作用域在程序的世界里,见怪不怪,谁都知道它的第一要务就是防止命名冲突!
Carl点点头,道:嗯,教材里是这么说的。他抬头看了一下光,阴影里有种烦躁的情绪在跳动。
其实,作用域是分类别的。Lisp中用到了其中之一的动态作用域(Dynamic Scope),动态作用域最根本的特点是从时间维度上判断进入和离开某个函数具有独立的作用域。上面Lisp的例子当中,let ((x 2)) (funcall f 2)表示一个函数,也就是独立的作用域。它调用了f这个函数,但从时间上看,调用点依旧处于原来的作用域当中,所以x=2这样的变量在f函数里是有效的,最后的结果是(* 2 y),等于4也就理所应当了。
Carl接受了这样的解释,他想:既然存在,那么一定合理。闭目养神的时间里,他的思维遨游了很久,有溺水的迹象,仿佛得到了神启。他想到了人生,理想,家人,婚姻和python2
在python2里面,这个世界里有怪物存在——嵌套的函数和外部作用域的再绑定。
x = "global" def foo(): x = "foo" def bar(): print x bar() foo()
答案是global,而不是想当然的foo。python2里头使用了静态作用域(Static Scope), 与动态作用域相对。静态作用域的显著特点是源码级别上拥有独立的作用域,简单地可以理解成每一个函数都是独立的作用域。然后,2011年发布的python2.1修改了逻辑,最终返回了foo,他们显然认为嵌套的函数不是函数,而是形同if/else这样的嵌套结构体。感觉上,又回到了当初动态作用域的年代。
Carl咽了口水,他讨厌动态作用域如同父母窥视了孩子狭小私人空间,这让他很不舒服。有一首诗:阴郁的日子总会过去。接下来,事情总算不太坏。
def foo(): x = "old" def bar(): x = "new" bar() print x foo()
这回得到的还是old。
Carl笑了,这才像话。
def foo(): x = "old" def bar(): nonlocal x x = "new" bar() print x foo()
这回得到的却是new。
Carl哭了。他想起来了,java里的类,private, protected修饰符,还有静态变量。他触摸到了作用域的本质,如同一直看不见的手,抚摸那薄膜面纱背后吹弹可破的脸蛋。至于有没有被赐予洪亮的耳光,那已经是后话了。
相关文章推荐
- 学语言不是写程序! 推荐
- 【转】程序语言不是工具
- ref: 这正是BI工具的精髓:它不是让你相信自己所知道的,而是促使你去思考更多的问题和疑惑。
- 你知道的,javascript语言的执行环境是"单线程模式",这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行,因此很多时候需要进行“异步模式”,请列举js异步编程的方法。
- 程序语言间不是问题
- 程序语言中的方言[]
- 用 XML 设计一个你自己的程序语言
- 开发多语言版本程序应注意的几个问题
- 你该学什么程序语言?[转贴:蔡学墉]
- 你该学什么程序语言?[转贴:蔡学墉]
- 如何取得正在运行的程序名(不是进程名)
- C语言经典程序!!--------------------------转自C语言经典论坛
- Application.Exit()并不是在什么地方都能终止程序的运行
- 汇编语言编写方法及程序分析
- 用 XML 设计一个你自己的程序语言
- 程序语言漫谈
- 用winrar的脚本语言,实现程序的自动打包
- UTF-8到acsii的转换(让自己的C++程序支持多语言)
- 计算机和现实世界的接口——程序语言
- 一个小语言的词法分析程序原理及其实现(2)