使用混合或继承更新字段的默认值

Update the default value of a field with a mixin or inheritance

假设我有一些 class snack,字段为 banana?:

(define snack%
  (class object%
    (super-new)
    (init-field [banana? #f])))

这样做,我可以构造我的 snack% 是否有 banana?,默认情况下没有 banana?:

(get-field banana? (new snack%))

(get-field banana? (new snack%
                        [banana? #f]))

(get-field banana? (new snack%
                        [banana? #t]))

评估为:

#f
#f
#t

符合预期。

但是,现在我想构建一个 snack-mixin class,它需要一个 snack% class(或者实际上,任何 class banana? 字段),并将该字段的默认值更改为 #t.

不幸的是,我似乎无法找到一种方法来修改继承的 class(如 mixin 中所定义)的默认值。我无法修改它,然后在我调用 super-new 之后 set-field!,就像我在这里所做的那样:

(define (snack-mixin %)
  (class %
    (super-new)
    (set-field! banana? this #t)))

虽然这确实将默认值从 #f 更改为 #t

(get-field banana? (new (snack-mixin snack%))) ; => #t

它还有一个负面影响,即忽略传递到 banana? 字段的任何内容,并将其设置为 #t

(get-field banana? (new (snack-mixin snack%)
                        [banana? #f]))
    ; => #t

我有什么方法可以做一个 mixin,或者做一个 class 来继承 snack% 并保持相同的字段 banana? (如,不创建新字段), 但更改了默认值,同时仍然让用户在调用 new?

时选择它

你在那里使用的 super-new 形式实际上可以接受参数,就像 new 通常可以的那样。因此,只需创建您自己的 init 表单,构造一些默认为 #tinternal-banana? 对象,然后将其传递给 super-new,如此处完成:

(define (snack-mixin %)
  (class %
    (init [(internal-banana? banana?) #t])
    (super-new [banana? internal-banana?])))

使用此版本的 snack-mixin,您将获得所需的行为,banana? 字段默认为 #t,也可以设置为 #f

(get-field banana? (new (snack-mixin snack%)))

(get-field banana? (new (snack-mixin snack%)
                        [banana? #f]))

(get-field banana? (new (snack-mixin snack%)
                        [banana? #t]))

计算结果为:

#t
#f
#t

符合预期。

编辑:正如 Asumu 所指出的,您实际上不需要使用标识符 internal-banana?:

(define (snack-mixin %)
  (class %
    (init [banana? #t])
    (super-new [banana? banana?])))

但是,这意味着 banana? 变量和 class 中的 banana? 字段将绑定到两个单独的变量。