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

如何让R6对象的数组成员实现原地更新而非复制更新?

如何让R6对象实现数组的原地更新?

我们通过以下代码测试R6对象数组成员的更新行为:

require(R6)
Array <- R6Class(
  "Array",
  public=list(
    x=matrix(0,0,0),
    initialize=function(a,b,c){
      self$x <- matrix(a,b,c)
    },
    assign=function(z){
      self$x[1,1] <- z
      invisible(self)
    }
  )
)
x <- Array$new(0,10,10)
tracemem(x$x)
x$assign(1)
y <- matrix(0,10,10)
tracemem(y)
y[1,1] <- 1

运行后得到输出:

> [1] "<0x55ae7be40040>"
> tracemem[0x55ae7be40040 -> 0x55ae7b403700]: <Anonymous> 
> > [1] "<0x55ae7b254c90>"
> > 

测试结果显示:更新R6对象的数组成员时会生成数组副本,而更新普通数组时则是原地更新(即不生成副本)。

问题原因

当执行self$x[1,1] <- z时,R会先取出self$x的副本,修改副本后再重新赋值给self$x,这个过程触发了副本创建。

解决方案

要实现原地更新,需要绕过R6的成员访问器直接操作底层环境,有两种可行方式:

方式1:直接操作R6对象的环境

修改assign方法,直接从对象的环境中获取数组并修改,避免取值时生成副本:

require(R6)
Array <- R6Class(
  "Array",
  public=list(
    x=matrix(0,0,0),
    initialize=function(a,b,c){
      self$x <- matrix(a,b,c)
    },
    assign=function(z){
      env <- environment(self)
      env$x[1,1] <- z
      invisible(self)
    }
  )
)

方式2:使用<<-操作符

在方法内部使用<<-,它会在当前环境的父环境(即R6对象的环境)中查找变量并直接修改,无需生成副本:

require(R6)
Array <- R6Class(
  "Array",
  public=list(
    x=matrix(0,0,0),
    initialize=function(a,b,c){
      self$x <- matrix(a,b,c)
    },
    assign=function(z){
      x[1,1] <<- z
      invisible(self)
    }
  )
)

验证效果

用修改后的代码重新测试,tracemem不会输出副本创建的日志,说明实现了原地更新:

x <- Array$new(0,10,10)
tracemem(x$x)
x$assign(1)

原理说明

R6对象的成员存储在其对应的环境中,self$x的访问会触发一次取值操作,对这个取值结果的修改会默认生成副本。而直接操作环境变量或使用<<-,可以直接修改原始数组对象,避免副本生成。

内容的提问来源于stack exchange,提问作者user1407220

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 13:10:27