R - 访问同一级别上另一个函数中定义的变量的函数

时间:2016-12-11 20:12:27

标签: r

所以我现在正处于项目中间,而且我遇到了范围问题。以下是我的问题的简化。

a <- function() {
  x <- 1:3    ## x is defined in a()
  w <- d()
  x
  w
}

b <- function() {
  y <- x[2]   ## I want to access x from b()
  x <- x[-2]  ## and modify x
  return(y)
}

d <- function() {
  z <- b()    ## then call b() from d()
  return(list(1, z, 3, 4))
}
a()

当我运行a()时,理想输出为w等于list(1, 2, 3, 4)x等于c(1, 3)。我知道我可以在全球范围内定义x,但x应该是不可见的&#39;到d()。 我尝试在parent.frame()中使用b(),但它不起作用,可能是因为d()是其父级而不是a()。我也和environment()搞混了,但我在理解结构方面遇到了麻烦。

1 个答案:

答案 0 :(得分:1)

1)本地环境我们可以在共享x的本地环境中定义功能。由于xbd仅在内部使用,因此我们只需将a提供回工作区。

a <- local({
  x <- NULL
  b <- function() { y <- x[2]; x <<- x[-2]; y }  
  d <- function() { z <- b(); list(1, z, 3, 4) }
  function() { x <<- 1:3; d() }
})

,并提供:

> x  # x should not be visible
Error: object 'x' not found

> a()
[[1]]
[1] 1

[[2]]
[1] 2

[[3]]
[1] 3

[[4]]
[1] 4

2)嵌套函数另一种方法是嵌套函数:

a <- function() {
  b <- function() { y <- x[2]; x <<- x[-2]; y }  
  d <- function() { z <- b(); list(1, z, 3, 4) }
  x <- 1:3
  d() 
}
a()

,并提供:

[[1]]
[1] 1

[[2]]
[1] 2

[[3]]
[1] 3

[[4]]
[1] 4

3)使用对象模型

虽然这允许我们在a不可见的情况下运行x,但最好使用其中一个R对象模型来定义a,{{1}的对象}和b是该对象的方法,d是属性。

proto包实现了一个基于纯对象的模型(即没有类),这在这里似乎特别适用:

x

,并提供:

library(proto)
p <- proto(x = NULL,
     b = function(.) { y <- .$x[2]; .$x <- .$x[-2]; y},
     d = function(.) { z <- .$b(); list(1, z, 3, 4) },
     a = function(.) { .$x <- 1:3; .$d() }
)
p$a()

原型代码也可以用(1)和(2)的样式编写,但继承不起作用。因为我们在这里不使用它可能无关紧要。

[[1]]
[1] 1

[[2]]
[1] 2

[[3]]
[1] 3

[[4]]
[1] 4

4)使x不可见如果你真的想让library(proto) p <- proto(x = NULL, b = function(.) { y <- x[2]; x <<- x[-2]; y}, d = function(.) { z <- b(); list(1, z, 3, 4) }, a = function(.) { x <<- 1:3; d() } ) p$a() x不可见,那么(1)将其更改为:

d

实际上如果L <- local({ x <- NULL list(b = function() { y <- x[2]; x <<- x[-2]; y }, a = function() { x <<- 1:3; d() }) }) d <- function() { z <- L$b(); list(1, z, 3, 4) } L$a() 真的想要到达d它可以像这样访问它;但是,人们真的需要付出努力:

x

对于(2)我们将代码更改为:

environment(a)$x

同样,L <- function() { x <- NULL list(b = function() { y <- x[2]; x <<- x[-2]; y }, a = function() { x <<- 1:3; d() }) } L <- L() d <- function() { z <- L$b(); list(1, z, 3, 4) } L$a() 实际上可以访问d,但同样需要付出相当大的努力:

x

对于(3)我们将代码更改为:

environment(L$a)$x

与(1)和(2)一样,如果我们真的想通过,我们可以从library(proto) p <- proto(.x = NULL, b = function(.) { y <- .$.x[2]; .$x <- .$.x[-2]; y}, a = function(.) { .$.x <- 1:3; d() } ) d = function() { z <- p$b(); list(1, z, 3, 4) } p$a() 访问x

d

但是从对象外部访问点变量会非常明显。

注意:根据评论,您可能更喜欢这样:

p$.x

这清楚地表明e <- local({ self <- environment() x <- NULL a <- function() { self$x <- 1:3; d(self) } b <- function() { y <- x[2]; self$x <- x[-2]; y } self }) d <- function(e) { z <- e$b(); list(1, z, 3, 4) } e$a() 被识别为ea是方法且b是属性且x正在行动的对象在通过的环境。它还避免了评论中提到的丑陋的d

虽然不太受欢迎,但您可以省略environment(a)$b()的参数,只需将d硬编码到e。请注意,d可以通过d访问x,因此它并非真正隐身,但必须付出额外的努力才能获得资格。这不太受欢迎的原因是,通过将e$x硬编码到e,我们将dd联系起来。在这种情况下,将e放在d中更合乎逻辑,因为它无论如何都要绑定。另一方面,如果我们将e传递给e,则d与任何特定环境无关。