24

当我查看 R 函数时,我经常会发现以下结构:

f <- function(exp=T) {
  if (exp)
    a <- 1
  else
    a <- 2
}
f()
f(F)

这将毫无错误地运行。但是执行内部函数代码会引发错误,因为 R 可能假定语句在第一次赋值后完成a <- 1并且无法处理以下 else。

exp=T
if (exp)
  a <- 1
else
  a <- 2

现在,这对我来说很有意义,但我仍然想了解为什么在函数内部或外部执行时,执行代码的行为会有所不同。

4

2 回答 2

35

执行摘要:

R 只有两种方法可以知道 else 子句属于它上面的 if 子句:

  1. 整个 if...else 语句(可能还有其他语句)都用大括号括起来;
  2. else 一词与 if 子句的结尾出现在同一行。

证据:

上面的讨论对我有帮助,但我希望我能提供一个有用的狡辩。是的,这是正确的

f <- function (exp)
    if (exp)
        1  
    else
        2

由于 R 未能继续阅读超过 1 ,经典Error: unexpected 'else' in "else"消息失败。已正确提供了两种方法来使 R 继续阅读超过 1:

f <- function (exp) {
    if (exp)
        1  
    else
        2
}

f <- function (exp) if (exp) 1 else 2

但是还有第三种方法还没有提到——else向上移动一条线。因此,以下内容也有效,因为 R 知道继续阅读 1:

f <- function (exp)
    if (exp)
        1  else
        2

我认为关键是要么支撑整个函数体,要么确保它else与 if 子句的末尾出现在同一行,以便 R 知道继续阅读。这就是单线解决方案有效的原因。这也是为什么它有效的原因:

f <- function (exp)
    if (exp) {
        1
    } else
        2

但这失败了:

f <- function (exp)
    if (exp) {
        1
    }  
    else
        2

并且使用更标准的函数体支撑,这也有效:

f <- function (exp) {
    if (exp) {
        1
    }  
    else
        2
}

但是我们是否正在构建一个函数是一个红鲱鱼。重要的只是大括号和else. 因此,这些工作:

{
    if (exp) {
        1
    }  
    else
        2
}


if (exp) {
    1
} else
    2

但这失败了:

if (exp) {
    1
} 
else
    2

并在顶部展示我的断言 1,这是有效的:

{
x <- 4
if (exp) 
    1
else
    2
}
于 2012-12-14T20:40:30.137 回答
30

这是使用交互式 shell ( REPL ) 运行脚本的结果:

在第一个分支之后,shell 已经看到了一个完整的语句,因此它假定您已经完成了输入。不幸的是,R 使用相同的 shell 来解释脚本,即使它们不是以交互方式输入的——所以即使你将if语句保存到文件中并且source它(或将其通过管道传输到 R 中)你也会在else分支上得到错误。

但以下将正常工作:

if (exp) a <- 1 else a <- 2

在这里,解释器吞下该行并执行它。

在你的函数中,人们会假设这同样适用——<em>确实如此!但是,在您的情况下,函数本身以左大括号开头,因此 R 必须读取直到找到匹配的右大括号。相比之下,采用以下函数声明:

f <- function (exp)
    if (exp)
        a <- 1
    else
        a <- 2

在 R 中,您可以在主体周围定义没有大括号的函数。if但是上面的代码将失败,原因与没有大括号的独立失败的原因相同。相比之下,如果我if在单行上编写了该代码,则该代码将再次起作用。

顺便说一句,您的函数使用对未使用变量的赋值。您可以(应该)执行以下操作:

f <- function (exp) {
    if (exp)
        1
    else
        2
}

......if在外壳内使用时也是如此:

a <- if (exp) 1 else 2

因为在 R 中,if是一个返回值的表达式。

于 2012-12-05T13:16:52.003 回答