设置在 Racket 中定义的相同 class 的另一个对象实例的私有字段

Setting private fields of another object instance of the same class being defined in Racket

假设我在 Racket 中有一些 class 叫做 five%:

(define five%
  (class object%
    (super-new)
    (define internal 5)
    (define/public (get-number)
      internal)))

假设我定义了两个五:

(define f (new five%))
(define g (new five%))

现在,fg 都可以访问他们自己的 internal 字段。但是假设我想向 five% 添加一个函数,称为 change-other,它接受另一个 five% 对象,并修改它的 internal 字段。像这样说:

(define/public (change-other other)
  (set-field! internal other 4))

现在,显然我不能这样做,因为 internal 是一个私有字段,因此它不能被 five% 的任何其他实例访问。

那么,是否可以在 Racket 中创建一个带有私有字段的 class,它只能被该 class 的其他实例访问?

诀窍是将字段设置为 public,然后使用 define-local-member-name 将其设为私有。

代码如下所示:

(define five%
  (let ()
    (define-local-member-name internal)
    (class object%
      (super-new)
      (field [internal 5])
      (define/public (change-other other)
        (set-field! internal other 4))
      (define/public (get-number)
        internal))))

(field [internal 5]) 行替换了私有字段的定义,并创建了一个 public 变体。

然后,在class相同的范围内,我们使用(define-local-member-name internal),将其转为class范围之外的私有字段。

现在,我们可以创建两个 five% 对象:

(define f (new five%))
(define g (new five%))

并且在 repl 中,我们看到 g 可以改变 f 的字段:

> (send g change-other f)
> (send f get-number)
4

但是我们不能直接改变它:

> (get-field internal f)
get-field: given object does not have the requested field
  field name: internal
  object: (object:five% ...)

感谢 Asumu 帮助回答这个问题。