使 R 函数返回锁定/不可变列表

mic*_*ael 5 r immutability

我有一个返回列表的函数。我希望这个列表是不可变的,类似于 lockBinding 防止覆盖或编辑对象的方式。

这看起来像下面这样:

myfun <- function(x){
    out <- list(a = 1, val = x)
    make_read_only(out)
    out
}
test <- myfun(9)
test$a
[1] 1

test$val
[1] 9

test
$a
[1] 1

$val
[1] 9

test$newval <- 7
Error:
Run Code Online (Sandbox Code Playgroud)

其中make_read_only()只是完成此任务的函数或某些代码的代表。

我尝试过使用 lockBinding ,它可以完美工作,但是在函数返回其输出后,“锁”无法向上传递到父环境中。我还考虑过尝试在父环境中锁定符号,但似乎没有办法了解函数内部的输出将分配给什么,而函数内部需要将其作为 lockBinding 的参数。

似乎有一种方法可以通过返回对环境的引用并使用 lockEnvironment() 锁定环境或执行类似的操作来实现此目的,但我想听听在开始之前有哪些选项可以实现此目的。类似地,使用 R6 似乎可以实现,但我宁愿避免使用 R6,因为此代码库的任何其他部分都不需要它,而且我只是想听听可以使用哪些选项来实现此行为。

总之,该函数将返回任意列表。这个列表至少有几个层次。

mylist <- myfun(list(b = list(c = 3), foo = "bar"))
Run Code Online (Sandbox Code Playgroud)

用户应该能够以类似于当前美元符号访问的直接方式访问子元素/元素

mylist$a$b$c
[1] 3
Run Code Online (Sandbox Code Playgroud)

应该无法编辑该对象。

mylist$a <- 5
Error:
Run Code Online (Sandbox Code Playgroud)

应该可以通过删除对象

rm(mylist)
mylist
Error: object 'mylist' not found
Run Code Online (Sandbox Code Playgroud)

所以我的问题是,R 中有哪些可用选项可以实现此目的?

iod*_*iod 4

实现此目的的一种方法是创建一个新类 ( locked) 以及该新类的[<-[[<-、 和方法$<-,这将返回错误。

例如:

`[[<-.locked` <- function(...) {stop("Can't assign into locked object")}
a<-list(a="a",b=2)
a
  $a
  [1] "a"

  $b
  [1] 2

class(a)<-"locked"
a[[1]]<-"moose"
  Error in `[[<-.locked`(`*tmp*`, 1, value = "moose") : 
    Can't assign into locked object

a
  $a
  [1] "a"

  $b
  [1] 2

  attr(,"class")
  [1] "locked"
Run Code Online (Sandbox Code Playgroud)

在这种情况下,所有“使只读”函数需要做的就是将对象的类重新定义为locked

class(out)<-c("locked",class(out))
Run Code Online (Sandbox Code Playgroud)