R中的赋值运算符=
和<-
之间有什么区别?
我知道运营商略有不同,如本例所示
x <- y <- 5
x = y = 5
x = y <- 5
x <- y = 5
# Error in (x <- y) = 5 : could not find function "<-<-"
但这是唯一的区别吗?
答案 0 :(得分:611)
当您使用它们在函数调用中设置参数值时,assignment operators的差异会更明显。例如:
median(x = 1:10)
x
## Error: object 'x' not found
在这种情况下,x
在函数范围内声明,因此在用户工作区中不存在。
median(x <- 1:10)
x
## [1] 1 2 3 4 5 6 7 8 9 10
在这种情况下,x
在用户工作区中声明,因此您可以在函数调用完成后使用它。
R社区普遍倾向于使用<-
进行分配(功能签名除外)以兼容(非常)旧版本的S-Plus。请注意,空格有助于澄清诸如
x<-3
# Does this mean assignment?
x <- 3
# Or less than?
x < -3
大多数R IDE都有键盘快捷键,可以让<-
更容易输入。建筑师中的 Ctrl + = ,RStudio中的 Alt + - ( Option + <在emacs + ESS中,kbd> - 在macOS下), Shift + - (下划线)。
如果您希望将=
写入<-
,但希望对公开发布的代码使用更常见的分配符号(例如,在CRAN上),那么您可以使用{{3}之一formatR
包中的函数会自动将=
替换为<-
。
library(formatR)
tidy_source(text = "x=1:5", arrow = TRUE)
## x <- 1:5
问题的答案“为什么x <- y = 5
抛出错误而不是x <- y <- 5
?”是“这取决于解析器中包含的魔力”。 R的语法包含tidy_*
,必须以某种方式解析。解析器选择以不同的顺序解析表达式的位,具体取决于是使用=
还是<-
。
要了解正在发生的事情,您需要知道该任务会以静默方式返回已分配的值。您可以通过显式打印更清楚地看到,例如print(x <- 2 + 3)
。
其次,如果我们使用前缀表示法进行分配,则更清楚。所以
x <- 5
`<-`(x, 5) #same thing
y = 5
`=`(y, 5) #also the same thing
解析器将x <- y <- 5
解释为
`<-`(x, `<-`(y, 5))
我们可能希望x <- y = 5
成为
`<-`(x, `=`(y, 5))
但实际上它被解释为
`=`(`<-`(x, y), 5)
这是因为=
的优先级低于<-
,如many ambiguous cases帮助页面所示。
答案 1 :(得分:97)
Google的R风格指南通过禁止分配“=”来简化问题。不错的选择。
https://google.github.io/styleguide/Rguide.xml
R手册详细介绍了所有5个赋值运算符。
http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html
答案 2 :(得分:31)
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
了解优先级(绑定)和分组规则。
答案 3 :(得分:30)
根据John Chambers的说法,运算符=
只允许在“顶级”,这意味着它不允许在if
之类的控制结构中,这使得以下编程错误非法。
> if(x = 0) 1 else x
Error: syntax error
正如他所写的那样,“在控制表达式中不允许使用新的赋值形式[=]可以避免编程错误(例如上面的例子),这些错误更可能与运算符相同而不是其他S赋值。”
如果“与周围的逻辑结构,大括号或一对额外的括号隔离”,您可以设法执行此操作,因此if ((x = 0)) 1 else x
可以正常工作。
答案 4 :(得分:24)
R中的赋值运算符
=
和<-
有什么区别?
如您的示例所示,=
和<-
的运算符优先级略有不同(确定它们混合在同一表达式中时的求值顺序)。实际上,R中的?Syntax
从最高到最低给出了以下运算符优先级表:
… ‘-> ->>’ rightwards assignment ‘<- <<-’ assignment (right to left) ‘=’ assignment (right to left) …
但这是唯一的区别吗?
由于您要询问赋值运算符:是的,那是唯一的区别。但是,您会相信其他理由。甚至?assignOps
的R文档都声称存在更多差异:
运算符
<-
可以在任何地方使用, 而运算符=
仅在最高级别(例如, 在命令提示符下键入的完整表达式中)或作为一个 大括号的表达式列表中的子表达式。
我们不要太在意: R文档是(很巧妙)错误 [1] 。这很容易显示:我们只需要找到=
运算符的反例,它不是(a)在顶层,也不是(b)在括号列表中的子表达式(即{ {1}})。 -事不宜迟
{…; …}
很明显,我们已经在上下文(a)和(b)之外使用x
# Error: object 'x' not found
sum((x = 1), 2)
# [1] 3
x
# [1] 1
进行了分配。那么,为什么几十年来一直错误地记录核心R语言功能的文档?
这是因为在R的语法中,符号=
具有两种通常会被混淆的含义:
=
运算符不同,它在运行时不执行任何操作,仅改变了表达式的解析方式。让我们看看。
以任何常规形式的代码...
=
… ‹function_name›(‹argname› = ‹value›, …)
‹function_name›(‹args›, ‹argname› = ‹value›, …)
是定义命名参数传递的令牌:它不是赋值运算符。此外,在某些语法上下文中,=
完全是禁止:
=
其中任何一个都会引发错误“ ‹bla›中出现意外'='”。
在任何其他上下文中,if (‹var› = ‹value›) …
while (‹var› = ‹value›) …
for (‹var› = ‹value› in ‹value2›) …
for (‹var1› in ‹var2› = ‹value›) …
指的是赋值运算符调用。特别是,仅在子表达式两边加上括号即可使以上(a)以及(b)赋值中的任何一个有效。例如,以下执行分配:
=
而且:
median((x = 1 : 10))
现在您可能会反对这样的代码是残酷的(您可能是正确的)。但是我从if (! (nf = length(from))) return()
函数中获取了这段代码(将base::file.copy
替换为<-
)—在许多核心R代码库中,这是一种普遍的模式。
R文档可能基于的original explanation by John Chambers实际上正确地解释了这一点:
[{
=
分配]仅在语法的两个位置允许:顶级(作为完整程序或用户键入的表达式);并且通过括号或多余的一对括号与周围的逻辑结构隔离时。
坦白:我早些说谎。 =
和=
运算符之间还有一个另外的区别:它们调用不同的函数。默认情况下,这些功能执行相同的操作,但是您可以分别覆盖其中的任何一个以更改行为。相比之下,<-
和<-
(从左到右的分配)尽管在语法上是不同的,但始终调用 same 函数。覆盖一个也覆盖另一个。知道这一点很少是实用的but it can be used for some fun shenanigans。
答案 5 :(得分:22)
运算符<-
和=
分配到评估它们的环境中。运算符<-
可以在任何地方使用, ,而运算符=
只允许在顶级 (例如,在输入的完整表达式中命令提示符)或作为支持的表达式列表中的子表达式之一。
答案 6 :(得分:5)
这也可以增加对这两个运营商之间差异的理解:
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 ...
R版本3.3.2(2016-10-31); macOS Sierra 10.12.1