首页 > 解决方案 > 在函数中添加全局 S3 对象的类,避免使用 `<<-` 运算符

问题描述

我在函数内定义一个 S3 对象并将其分配给全局环境中的变量;随后在同一个函数中,我向它添加了一个额外的类。我能够做到这一点的唯一方法是使用<<-运算符,我宁愿避免在阅读时它实际上分配给父环境,这可能很危险。理想情况下,我想使用assign,但第一个参数是变量名,所以它失败了。关于如何在不使用的情况下更好地实现这一点的任何建议<<-

作为记录,我也尝试了正常的赋值运算符<-,但这也失败了,不明白为什么,因为变量已经在全局范围内定义。

下面的一些说明性示例:

# <<- assigns to parent environment, if "lucky" that is the globalenv, me no gusto :(
foo_works_dragons <- function(addclass) {
  fooobj <- structure(list(), class = "Alpha")
  assign("G_FOOOBJ", fooobj, envir = globalenv())
  class(G_FOOOBJ) <<- c(class(G_FOOOBJ), addclass)
  return(TRUE)
}


# prefer assign statement but function argument x is "a variable name" from man page, so ok not working, any suggestions?
foo_fails_nodragons <- function(addclass) {
  fooobj <- structure(list(), class = "Alpha")
  assign("G_FOOOBJ", fooobj, envir = globalenv())
  assign("class(G_FOOOBJ)", c(class(G_FOOOBJ), addclass), envir = globalenv())
  return(TRUE)
}


# fails, don't understand though why
foo_fails_but_why <- function(addclass) {
  fooobj <- structure(list(), class = "Alpha")
  assign("G_FOOOBJ", fooobj, envir = globalenv())
  class(G_FOOOBJ) <- c(class(G_FOOOBJ), addclass)
  return(TRUE)
}


foo_works_dragons("Beta")
print(class(G_FOOOBJ))
# [1] "Alpha" "Beta"
rm(G_FOOOBJ)

foo_fails_nodragons("Beta")
print(class(G_FOOOBJ))
# [1] "Alpha"
rm(G_FOOOBJ)

foo_fails_but_why("Beta")
print(class(G_FOOOBJ))
# [1] "Alpha"
rm(G_FOOOBJ)

标签: r

解决方案


使用 envir$object 表示法:

foo <- function(addclass, envir = .GlobalEnv) {
  envir$G_FOOOBJ <- structure(list(), class = "Alpha")
  class(envir$G_FOOOBJ) <- c(class(envir$G_FOOOBJ), addclass)
  return(TRUE)
}

if (exists("G_FOOOBJ")) rm(G_FOOOBJ)
foo("Beta")
## [1] TRUE

G_FOOOBJ
## list()
## attr(,"class")
## [1] "Alpha" "Beta" 

如果你真的想使用,assign那么这个工作:

foo2 <- function(addclass, envir = .GlobalEnv) {
  fooobj <- structure(list(), class = "Alpha")
  assign("G_FOOOBJ", structure(fooobj, class = c(class(fooobj), addclass)), envir)
  return(TRUE)
}

if (exists("G_FOOOBJ")) rm(G_FOOOBJ)
foo2("Beta")
## [1] TRUE

G_FOOOBJ
## list()
## attr(,"class")
## [1] "Alpha" "Beta" 

推荐阅读