为什么这个简单的功能不起作用?

时间:2017-11-25 12:25:13

标签: r function

我首先定义了新的变量x,然后在其体内创建了需要x的函数(而不是参数)。见下面的代码

x <- c(1,2,3)
f1 <- function() {
  x^2
}

rm(x)

f2 <- function() {
  x <- c(1,2,3)
  f1()
}

f(2)  
Error in f1() : object 'x' not found

当我删除x并定义首先定义f2然后执行x的新功能f1时,它会显示找不到的对象x

我只是想知道为什么这不起作用以及如何克服这个问题。我不希望xf1中成为名称作为参数。

请提供适当的标题,因为我不知道这是什么问题。

2 个答案:

答案 0 :(得分:6)

您可以使用closure制作具有所需属性的f1

makeF <- function(){
  x <- c(1,2,3)
  f1 <- function() {
    x^2
  }
  f1
}

f1 <- makeF()
f1() #returns 1 4 9

全局范围内没有x,但f1仍然知道它所定义的环境中的x

答案 1 :(得分:4)

简而言之:您期待动态范围但是R的词汇范围的受害者:

  • 动态范围=在运行时确定命令的封闭环境

  • 词法范围=命令的封闭环境在&#34;编译时确定&#34;

要了解当前和父环境中变量x的查找路径,请尝试使用此代码。

它表明这两个函数不共享x中的f2定义的环境,因此无法找到它:

# list all parent environments of an environment to show the "search path"
parents <- function(env) {
  while (TRUE) {
    name <- environmentName(env)
    txt <- if (nzchar(name)) name else format(env)
    cat(txt, "\n")
    if (txt == "R_EmptyEnv") break
    env <- parent.env(env)
  }
}

x <- c(1,2,3)
f1 <- function() {
  print("f1:")
  parents(environment())
  x^2
}

f1()  # works
# [1] "f1:"
# <environment: 0x4ebb8b8> 
# R_GlobalEnv 
# ...

rm(x)

f2 <- function() {
  print("f2:")
  parents(environment())
  x <- c(1,2,3)
  f1()
}

f2()  # does not find "x"
# [1] "f2:"
# <environment: 0x47b2d18> 
# R_GlobalEnv
# ...
# [1] "f1:"
# <environment: 0x4765828> 
# R_GlobalEnv 
# ...

可能的解决方案:

  1. 在全局环境中声明x(由于缺少封装而导致编程风格不佳)

  2. 使用函数参数(这是函数的作用)

  3. 如果x每次调用f1时始终具有相同的值,则使用闭包(不适合初学者)。请参阅@JohnColeman的其他答案......

  4. 我强烈建议使用2.(添加x作为参数 - 为什么要避免这种情况?)。