假设我在Racket中定义了一个包含大约30个字段的类。
我想把它们视为不可变的。换句话说,我永远不会更新对象,只需创建一个新对象,其中29个字段包含相同的值,另一个具有覆盖的值。
是否有任何便利功能?
目前,我正在费力地编写像
这样的函数(define/public (overwrite-n n-val)
(new MyClass% [a (get-a)] [b (get-b)] [c (get-c)] ... [n n-val] ... ))
我希望能够更新的每个字段。必须有更好的方法来做到这一点。
答案 0 :(得分:3)
如果你想进行这样的功能更新,你可能最好使用结构,那里提供了struct-copy
和generic interfaces等工具。
如果您确实需要使用racket/class
,那么一个选项(如果这些是公共字段并且都使用init-field
声明)使用反射机制和私有racket/class
实现细节,如来自class-info
的{{1}}和do-make-object
。为了好玩,我制作了一个类似于racket/private/class-internal
的{{1}}表单,这里有一个要点:object-copy.rkt
object-copy
另一种选择,如果您可以确定这些总是为真:
然后你可以覆盖getter方法来获得这种行为:
struct-copy
如果这些事情不对,或者你害怕有一天你会忘记并且他们会改变(很可能,特别是对于子类的事情),那么这会赢得&# 39;工作。如果#lang racket/base
(require racket/class
"object-copy.rkt")
(define my-class%
(class object%
(super-new)
(inspect #f)
(init-field a b c)
(define/public (get-a) a)
(define/public (get-b) b)
(define/public (get-c) c)
(define/public (update-a a)
(object-copy my-class% this [a a]))
(define/public (update-b b)
(object-copy my-class% this [b b]))
(define/public (update-c c)
(object-copy my-class% this [c c]))
))
(define obj
(new my-class%
[a 1]
[b 2]
[c 3]))
(send obj get-a)
; 1
(send (send obj update-a 4) get-a)
; 4
可以被子类化,那么使用#lang racket/base
(require racket/class)
(define my-class%
(class object%
(super-new)
(define/public (get-a) (error 'a "uninitialized"))
(define/public (get-b) (error 'b "uninitialized"))
(define/public (get-c) (error 'c "uninitialized"))
(define/public (update-a a)
(new (class this%
(super-new)
(define/override (get-a) a))))
(define/public (update-b b)
(new (class this%
(super-new)
(define/override (get-b) b))))
(define/public (update-c c)
(new (class this%
(super-new)
(define/override (get-c) c))))
))
(define obj
(send+ (new my-class%)
(update-a 1)
(update-b 2)
(update-c 3)))
(send obj get-a)
; 1
(send (send obj update-a 4) get-a)
; 4
并不是真正类型安全的。
虽然就像我在这个答案的顶部所说的那样,结构通常对这种类型的东西更好。