class - 如何覆盖类中字段的默认值?
问题描述
这是迄今为止我发现的覆盖类中默认字段值的最佳方法:
(define sa-canvas%
(class canvas%
. . .
(init-field [min-width 600]
[min-height 300]
[stretchable-width #f]
[stretchable-height #f])
(super-new [min-width min-width]
[min-height min-height]
[stretchable-width stretchable-width]
[stretchable-height stretchable-height])
. . .))
这对于 Racket 来说似乎太冗长了。Racket 的类系统旨在支持的预期方式是什么?
解决方案
首先,您的示例做了您可能不想要的事情。Usinginit-field
在类的实例上创建一个可变的公共字段,该字段已初始化为相应的初始化参数。这些并不经常使用:更常见的是使用私有字段(即define
)和 getter 方法,如果您想支持突变,可能使用 setter。事实上,我们可以看出,但是canvas%
使用这些初始化参数,它不会将它们存储为公共字段,因为(与方法一样)一个类不能创建一个与它的超类的字段具有相同外部名称的新字段. (字段可以用 . 继承inherit-field
。)例如,评估这个表达式会引发一个异常:
(class (class object%
(init-field [x 1])
(super-new))
(init-field [x 2])
(super-new [x x]))
对于您不想作为字段保留的初始化参数,请使用init
而不是init-field
. 此表达式与您的示例相同,但不创建字段:
(class canvas%
(init [min-width 600]
[min-height 300]
[stretchable-width #f]
[stretchable-height #f])
(super-new [min-width min-width]
[min-height min-height]
[stretchable-width stretchable-width]
[stretchable-height stretchable-height]))
不过,您是对的,这是要保持同步的大量输入和繁琐的代码。类库没有内置不同的方法,但是您可以使用一个小宏轻松地自己添加一个:
(class canvas%
(define-syntax-rule (init/super-new [name default] ...)
(begin (init [name default] ...)
(super-new [name name] ...)))
(init/super-new
[min-width 600]
[min-height 300]
[stretchable-width #f]
[stretchable-height #f]))
可以很容易地进入define-syntax-rule
模块级别,但是:
本地宏很酷;和
宏的一大优点是您不必处理一般情况:比如说,有时您可能还想将其他参数传递给
super-new
. 如果您愿意,您当然可以支持这一点,但是,对于宏,您和库编写者都不必提前预见您可能想要的所有可能的便利。编写一个简单的宏来使您的特定代码更具可读性是完全合法的。
推荐阅读
- apache-spark - flatMap 在 DataFrame 中创建多行
- c# - 如何在更改其值后在运行时保存 ScriptableObject
- c++ - 为什么迭代 std::array 比迭代 std::vector 快得多?
- powershell - 如何在powershell中将文件发送到蓝牙
- javascript - 在放入 MongoDB 之前压缩 JS 对象数组的最佳方法
- openlayers - Openlayers:将 Geocoder 控件添加到自定义 DIV
- c - 是否可以一起使用#define group 不同的变量
- shopify - ReferenceError: $ is not defined at dist/assets/theme.js?5556:274 in Shopify Slate 主题
- git - 工作流程推荐以及如何查看 git fetch 更改
- objective-c - 如何将数据从 collectionView 发送到另一个视图(Objective-C)