在函数内添加全局S3对象的类,避免使用<<-

时间:2018-12-03 23:49:09

标签: r

我正在函数内部定义一个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)

1 个答案:

答案 0 :(得分:1)

使用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"