Racket 类中的私有字段(或成员变量)

Lei*_*sen 5 class object racket

我有一个类counter%,它将计数器存储为字段,并提供方法get-and-inc, 来获取当前计数器的值并递增它。

(define counter%
  (class object%
    (super-new)
    (field [counter 0])
     (define/public (get-and-inc)
      (begin0 counter
              (set! counter (add1 counter))))))
Run Code Online (Sandbox Code Playgroud)

虽然此代码确实可以准确计数:

> (define x (new counter%))
> (send x get-and-inc)
0
> (send x get-and-inc)
1
Run Code Online (Sandbox Code Playgroud)

问题是计数器现在是公开的:

> (set-field! counter x 42)
> (send x get-and-inc)
42
> (send x get-and-inc)
43
Run Code Online (Sandbox Code Playgroud)

这里的问题是我希望该counter字段是私有的,以便实例化该类的人无法修改它。Racket 的等级系统可以做到这一点吗?

Lei*_*sen 2

对的,这是可能的。您需要做的就是定义它,就像定义类中的任何其他变量一样:

(define counter%
  (class object%
    (super-new)
    (define counter 0)
    (define/public (get-and-inc)
      (begin0 counter
              (set! counter (add1 counter))))))
Run Code Online (Sandbox Code Playgroud)

现在当你使用它时,每个对象都会有自己的计数器:

> (define x (new counter%))
> (define y (new counter%))

> (send x get-and-inc)
0
> (send y get-and-inc)
0
> (send x get-and-inc)
1
> (send y get-and-inc)
1
Run Code Online (Sandbox Code Playgroud)

这是因为类中定义的任何不是方法的变量都被假定为字段(根据文档

类中的每个字段、初始字段和非方法定义值子句都为该类声明一个或多个新字段。使用 field 或 init-field 声明的字段是公共的。子类可以使用继承字段来访问和改变公共字段。公共字段也可以在类外部通过 class-field-accessor 访问,并通过 class-field-mutator 可变(请参阅字段和方法访问)。使用定义值声明的字段只能在类内访问。

这意味着,如果您想要一个与类关联的静态变量,而不是实例化对象,则需要在类外部定义它。可能使用let块:

(define static-counter%
  (let ([counter 0])
    (class object%
      (super-new)
      (define/public (get-and-inc)
        (begin0 counter
                (set! counter (add1 counter)))))))
Run Code Online (Sandbox Code Playgroud)

现在所有static-counter对象将共享同一个计数器

> (define x (new counter%))
> (define y (new counter%))

> (send x get-and-inc)
0
> (send y get-and-inc)
1
> (send x get-and-inc)
2
> (send y get-and-inc)
3
Run Code Online (Sandbox Code Playgroud)