You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 00:53:21