Chez Scheme中Boxes介绍

Chez Scheme中有一种Boxes结构,它是一个单元素对象,主要用于提供一个“额外的间接层”。这个额外的间接层,通常用于使多个代码块或数据结构可以共享指向一个对象的引用,或指针。例如,在采用此种参数传递规则的语言的解释器中,可以用 boxes 实现 call-by-reference 的语义。解释有点绕,按我的理解boxes就相当于Golang的struct、Java中的类,将一些状态包装成一个整块,外界通过引用该整块的指针来访问内部的各个状态。

Boxes 的字面形式带有前缀 #& (发音为 “hash-ampersand”). 例如, #&(a b c) 是一个 box,内容为列表 (a b c). 读取器若遇到 #!r6rs ,则会在其后的输入流中禁用 box 语法,除非在更近的位置遇到 #!chezscheme.

所有 boxes 默认是可变的,包括常量。程序可以通过 box-immutable 创建不可变 boxes. 尝试修改不可变 box 会导致抛出异常。

我们来看看一些用法:


(box? obj)

如果 obj 是 box, 则为 #t, 否则为 #f.

(box? '#&a) => #t
(box? 'a) => #f
(box? (box 3)) => #t

(box obj)

创建一个由obj组成的box

(box 'a) => #&a
(box (box '(a b c))) => #&#&(a b c)

(unbox box)

返回box的内容

(unbox #&a) => a
(unbox #&#&(a b c)) => #&(a b c)

(let ([b (box "hi")])
  (unbox b)) => "hi"

(set-box! box obj)

box 必须是可变的。 set-box! 把 box 的内容设置为 obj.

(let ([b (box 'x)])
  (set-box! b 'y)
  b) => #&y

(let ([incr!
       (lambda (x)
         (set-box! x (+ (unbox x) 1)))])
  (let ([b (box 3)])
    (incr! b)
    (unbox b))) => 4

(box-cas! box old-obj new-obj)

如果 box 被改变,则为 #t, 否则为 #f. box 必须是可变的。 若 box 待替换的内容和 old-obj 相同(基于 eq?), 则 box-cas! 自动将 box 的内容替换为 new-obj; 若不相同,则 box 保持不变。即CAS操作,原子的。

(define b (box 'old))
(box-cas! b 'old 'new) => #t
(unbox b) => 'new
(box-cas! b 'other 'wrong) => #f
(unbox b) => 'new

(mutable-box? obj)

如果 obj 是可变的 box ,则为 #t, 否则为 #f.

(immutable-box? obj)

如果 obj 是不可变的 box ,则为 #t, 否则为 #f.

(box-immutable obj)

返回一个内容为obj的不可变的box。Boxes 通常用来支持共享的,可变的结构,所以不可变的 box 一般没什么用。