首页 > 解决方案 > 如何更改 $ 运算符在环境中的行为?

问题描述

我想覆盖美元运算符的行为,这样如果我有

x <- new.env()
x$foo <- 3

例如会打电话给某事。我试图寻找可能的功能,例如$,但我对内部的了解还不够好。

我试过这个:

`$` <- function(a, b) { 
    res <- .Primitive("$")(a, b); 
    print(res); 
    if(is.null(res)) { print("null!") }; 
    return(res) 
}

它似乎工作,但是:

> x$foobar
NULL
[1] "null!"
NULL
> x$foobar <- 3
> x$foobar
NULL
[1] "null!"
NULL
> 

因此,尽管被覆盖,它似乎仍然为空。

标签: r

解决方案


R s 的正常行为environment

myenv <- new.env(parent = emptyenv())
myenv$foo <- 3
class(myenv)
# [1] "environment"

myenv$foo
# [1] 3
myenv$foobar
# NULL

让我们定义一个超类(我会命名它environment2,在这里随意发挥创意)并覆盖$该类:

class(myenv) <- c("environment2", "environment")
`$.environment2` <- function(x, name) {
  stopifnot(name %in% names(x))
  NextMethod()
}
myenv$foo
# [1] 3
myenv$foobar
# Error in `$.environment2`(myenv, foobar) : name %in% names(x) is not TRUE

如果您愿意,可以使用带有 的if语句stop或(在 R-4 或更新版本中)将条件命名为stopifnot.

`$.environment2` <- function(x, name) {
  if (!name %in% names(x)) stop("something meaningful", call. = FALSE)
  NextMethod()
}
`$.environment2` <- function(x, name) {
  stopifnot(
    "something meaningful" = name %in% names(x)
  )
  NextMethod()
}

### both render
myenv$foobar
# Error in `$.environment2`(myenv, foobar) : something meaningful

它们是相对等价的,但是使用if/stop可以减少错误上下文:

`$.environment2` <- function(x, name) {
  if (!name %in% names(x)) stop("something meaningful", call. = FALSE)
  NextMethod()
}
myenv$foobar
# Error: something meaningful

推荐阅读