为何R6类设置lock_objects=FALSE仍无法覆盖动态创建的方法?
问题原因解析
错误的核心是R6对显式声明成员的绑定锁定规则:
- 当你在
Child类的public列表中显式定义foo方法时,R6会自动为这个成员创建一个锁定的绑定(locked binding),这个锁定和lock_objects = FALSE参数无关。 lock_objects = FALSE的作用仅允许给对象添加新的、未提前声明的成员,但不会解除对已显式声明成员的绑定锁定。
当Parent的initialize方法执行时,尝试给已经被Child显式声明并锁定的foo赋值,就会触发"cannot change value of locked binding for 'foo'"错误。
解决方案
根据需求,有两种常见处理方式:
方式一:移除Child中显式声明的foo
如果Child不需要提前定义foo的重写逻辑,直接删掉Child类public里的foo方法,让Parent动态创建:
Parent <- R6::R6Class( "Parent", lock_objects = FALSE, public = list( initialize = function() { self[["foo"]] <- function() { print('foo') } } ) ) Child <- R6::R6Class( "Child", inherit = Parent, lock_objects = FALSE ) child <- Child$new() child$foo() # 输出 [1] "foo"
方式二:解锁foo绑定后再修改
如果需要保留Child对foo的重写逻辑,同时允许Parent动态修改,可以在Child的initialize中先解锁foo的绑定,再调用父类的初始化方法:
Parent <- R6::R6Class( "Parent", lock_objects = FALSE, public = list( initialize = function() { self[["foo"]] <- function() { print('foo') } } ) ) Child <- R6::R6Class( "Child", inherit = Parent, lock_objects = FALSE, public = list( initialize = function() { unlockBinding("foo", self) super$initialize() }, foo = function() { super$foo() } ) ) child <- Child$new() child$foo() # 输出 [1] "foo"
注意:如果希望Child的foo重写逻辑不被父类覆盖,应该调整设计,避免在父类初始化中修改子类已显式声明的方法。
内容的提问来源于stack exchange,提问作者Paweł Chabros
相关产品推荐
相关产品推荐

