问题的答案“为什么 x <- y = 5 抛出错误而不是 x <- y <- 5 ?" is "它's down to the magic contained in the parser". R'的语法包含many ambiguous cases必须以某种方式解析 . 解析器选择以不同的顺序解析表达式的位,具体取决于 = 或 <- 被使用 .
坦白:我早先撒了谎 . = 和 <- 运算符之间还有一个区别:它们调用不同的函数 . 默认情况下,这些函数执行相同的操作,但您可以单独覆盖它们中的任何一个以更改行为 . 相比之下, <- 和 -> (从左到右的赋值)虽然语法上不同,但总是调用相同的函数 . 覆盖一个也会覆盖另一个 . 知道这很难实际but it can be used for some fun shenanigans .
16
这也可以增加对这两个运算符之间差异的理解:
df <- data.frame(
a = rnorm(10),
b <- rnorm(10)
)
对于第一个元素,R已经赋值和正确的名称,而第二个元素的名称看起来有点奇怪 .
str(df)
# 'data.frame': 10 obs. of 2 variables:
# $ a : num 0.6393 1.125 -1.2514 0.0729 -1.3292 ...
# $ b....rnorm.10.: num 0.2485 0.0391 -1.6532 -0.3366 1.1951 ...
7 回答
x = y = 5
相当于x = (y = 5)
,因为赋值运算符"group"从右到左,有效 . 含义:将5分配给y
,保留数字5;然后将该5分配给x
.这与
(x = y) = 5
不一样,这不起作用!含义:将y
的值赋给x
,保留y
的值;然后分配5,嗯......,到底是什么?混合不同类型的赋值运算符时,
<-
比=
更紧密 . 所以x = y <- 5
被解释为x = (y <- 5)
,这是有道理的 .不幸的是,
x <- y = 5
被解释为(x <- y) = 5
,这是不起作用的情况!有关优先级(绑定)和分组规则,请参阅
?Syntax
和?assignOps
.当您使用它们在函数调用中设置参数值时,assignment operators的区别更加清晰 . 例如:
在这种情况下,
x
在函数范围内声明,因此它不存在于用户工作空间中 .在这种情况下,
x
在用户工作区中声明,因此您可以在函数调用完成后使用它 .R社区普遍倾向于使用
<-
进行分配(功能签名除外)以兼容(非常)旧版本的S-Plus . 请注意,空格有助于澄清类似的情况大多数R IDE都有键盘快捷键,使
<-
更容易输入 . Ctrl = in Architect,Alt - 在RStudio中(选项 - 在macOS下),Shift - (下划线)在emacs ESS中 .如果您更喜欢将
=
写入<-
但希望对公开发布的代码使用更常见的赋值符号(例如,在CRAN上),则可以使用formatR
包中的tidy_*函数之一自动将=
替换为<-
.问题的答案“为什么
x <- y = 5
抛出错误而不是x <- y <- 5
?" is "它's down to the magic contained in the parser". R'的语法包含many ambiguous cases必须以某种方式解析 . 解析器选择以不同的顺序解析表达式的位,具体取决于=
或<-
被使用 .要了解发生的情况,您需要知道该任务以静默方式返回已分配的值 . 您可以通过显式打印更清楚地看到,例如
print(x <- 2 + 3)
.其次,如果我们使用前缀表示法进行赋值,则更清楚 . 所以
解析器将_665342解释为
我们可能会期待
x <- y = 5
但实际上它被解释为
这是因为
=
的优先级低于<-
,如?Syntax帮助页面所示 .Google的R风格指南通过禁止分配“=”来简化问题 . 不错的选择 .
https://google.github.io/styleguide/Rguide.xml
R手册详细介绍了所有5个赋值运算符 .
http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html
根据John Chambers的说法,运算符
=
仅允许在"the top level,",这意味着它不允许在像if
这样的控制结构中,这使得以下编程错误非法 .正如他所写的那样,“在控制表达式中不允许新的赋值形式[=]避免了编程错误(例如上面的例子),这些错误更可能与运算符相等而不是其他S赋值 . ”
你可以设法这样做"isolated from surrounding logical structure, by braces or an extra pair of parentheses,"所以
if ((x = 0)) 1 else x
会起作用 .见http://developer.r-project.org/equalAssign.html
运算符
<-
和=
分配到评估它们的环境中 . 运算符<-
可以在任何地方使用,例如,在命令提示符下键入的完整表达式中,或者作为支持的表达式列表中的子表达式之一 .如您的示例所示,
=
和<-
具有稍微不同的运算符优先级(这决定了它们在同一表达式中混合时的求值顺序) . 实际上,R中的?Syntax给出了以下运算符优先级表,从最高到最低:但这是唯一的区别吗?
既然你问的是赋值运算符:是的,那是唯一的区别 . 但是,如果不相信,你会被原谅 . 即使是?assignOps的R文档声称存在更多差异:
让我们不要过分细致: the R documentation is (subtly) wrong [1] . 这很容易显示:我们只需要找到
=
运算符的反例,它不是(a)在顶层,也不是(b)在表达式的支撑列表中的子表达式(即{…; …}
) . - 无需再费周折:显然,我们在上下文(a)和(b)之外使用
=
执行了一项任务 . 那么,为什么几十年来核心R语言功能的文档出错呢?这是因为在R的语法中,符号
=
有两个不同的含义,这些含义经常混淆:第一个含义是作为赋值运算符 . 这是我们到目前为止所讨论的全部内容 .
第二个含义不是运算符,而是一个语法标记,表示在函数调用中传递的命名参数 . 与
=
运算符不同,它在运行时不执行任何操作,它只是更改表达式的解析方式 .让我们来看看 .
在一般形式的任何代码中......
... = 是定义命名参数传递的标记:它不是赋值运算符 . 此外,在某些句法语境中完全禁止
=
:其中任何一个都会在<bla>中引发错误“unexpected'=' .
在任何其他上下文中,
=
指的是赋值运算符调用 . 特别是,仅在子表达式周围加括号使上述(a)中的任何一个有效,(b)赋值 . 例如,以下执行赋值:但是也:
现在你可能反对这样的代码是残暴的(你可能是对的) . 但是我从base :: file.copy函数中取代了这个代码(替换了<--with =) - 它在核心R代码库的大部分内容中都是普遍存在的模式 .
R文档可能基于的original explanation by John Chambers实际上正确地解释了这一点:
坦白:我早先撒了谎 .
=
和<-
运算符之间还有一个区别:它们调用不同的函数 . 默认情况下,这些函数执行相同的操作,但您可以单独覆盖它们中的任何一个以更改行为 . 相比之下,<-
和->
(从左到右的赋值)虽然语法上不同,但总是调用相同的函数 . 覆盖一个也会覆盖另一个 . 知道这很难实际but it can be used for some fun shenanigans .这也可以增加对这两个运算符之间差异的理解:
对于第一个元素,R已经赋值和正确的名称,而第二个元素的名称看起来有点奇怪 .
R版本3.3.2(2016-10-31); macOS Sierra 10.12.1