关于Scheme中set!与别名机制的困惑:两次操作结果为何不同?
搞懂Scheme中
set!和set-car!的核心区别 嘿,这个困惑太典型了!我刚学Scheme的时候也被这俩操作搞晕过,本质是没分清变量绑定和数据结构修改的区别,给你一步步拆解:
先看示例1:set!是修改变量绑定,不是修改对象
咱们把示例1的代码拆开来理解:
(define foo '(a b)) ; 把变量foo绑定到一个新创建的列表对象'(a b)上 (define bar foo) ; 让变量bar也绑定到同一个'(a b)对象 (set! foo '(c d)) ; 这里是修改foo的绑定——把它重新绑定到新的列表'(c d)上
重点在set!的作用:它根本没碰原来那个(a b)列表,只是把foo这个"指针"从原来的列表挪到了新列表上。而bar的"指针"还牢牢指着原来的(a b),所以bar的输出自然还是(a b)。
再看示例2:set-car!是直接修改数据结构本身
示例2的代码逻辑完全不同:
(define foo '(a b)) ; 同样,foo绑定到'(a b)对象 (define bar foo) ; bar也绑定到同一个对象 (set-car! foo 'c) ; 直接修改foo所指向的那个列表对象的car部分,把'a换成'c
set-car!是破坏性操作——它直接钻进了foo指向的列表对象内部,修改了这个对象的内容。因为bar和foo指向的是同一个对象,所以不管通过哪个变量去访问这个列表,看到的都是修改后的(c b)。
一句话总结核心差异
set!:操作的是变量和对象之间的绑定关系,相当于给变量换了个指向的对象,旧对象本身毫发无损。set-car!/set-cdr!:操作的是对象本身的内部结构,修改后所有指向这个对象的变量都会看到变化。
打个生活化的比方:foo和bar就像两把钥匙,一开始都能打开同一个柜子((a b))。set! foo是把foo这把钥匙改成开另一个新柜子((c d)),原来的柜子还是老样子;而set-car!是直接打开柜子,把里面第一个东西换成了c,不管用哪把钥匙开这个柜子,看到的都是换过的东西。
内容的提问来源于stack exchange,提问作者Kubelecer
相关产品推荐
相关产品推荐

