当我查看R函数时,我经常会发现以下结构:
f <- function(exp=T) {
if (exp)
a <- 1
else
a <- 2
}
f()
f(F)
这将运行没有错误。但是执行内部函数代码会引发错误,因为R可能假定语句在第一个赋值a <- 1
之后完成,并且无法处理以下其他内容。
exp=T
if (exp)
a <- 1
else
a <- 2
现在,这对我来说很有意义,但我仍然想了解为什么执行代码的行为在函数内部或外部执行时会有所不同。
答案 0 :(得分:28)
执行摘要:
R只有两种方法可以知道else子句属于它上面的if子句:
<强>证据:强>
上述讨论对我有所帮助,但我希望我能提供一个有用的狡辩。是的,这是正确的
f <- function (exp)
if (exp)
1
else
2
因经典Error: unexpected 'else' in "else"
消息而失败,因为R未能继续阅读1.已正确提供两种方法让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
}
答案 1 :(得分:27)
这是使用交互式shell(REPL)运行脚本的结果:
在第一个分支之后,shell看到了一个完整的语句,因此它假定你已完成输入。不幸的是,R使用相同的shell来解释脚本,即使它们没有以交互方式输入 - 所以即使将if
语句保存到文件并source
它(或将其管道输入R),您将在else
分支上获取错误。
但以下情况会很好:
if (exp) a <- 1 else a <- 2
这里,解释器吞下该行并执行它。
在你的函数中,人们会认为同样适用 - 并且确实如此!然而,函数本身在你的情况下以一个开括号开始,所以R必须读到它找到匹配的右括号。相比之下,请使用此函数声明:
f <- function (exp)
if (exp)
a <- 1
else
a <- 2
在R中,您可以定义身体周围没有括号的功能。但上述代码将失败的原因与没有大括号的独立if
失败的原因相同。相比之下,如果我在一行上写了if
,那么这段代码将再次起作用。
顺便提一下,您的函数使用对未使用的变量的赋值。您可以(应该)执行以下操作:
f <- function (exp) {
if (exp)
1
else
2
}
...在shell中使用if
时也一样:
a <- if (exp) 1 else 2
因为在R中,if
是表达式,它返回一个值。