赋值运算符=
和<-
R 之间有什么区别?
我知道运营商略有不同,如本例所示
x <- y <- 5 x = y = 5 x = y <- 5 x <- y = 5 # Error in (x <- y) = 5 : could not find function "<-<-"
但这是唯一的区别吗?
当您使用它们在函数调用中设置参数值时,赋值运算符的差异会更明显.例如:
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+ =在Architect中,Alt+ -在RStudio(Option+ -在macOS下),Shift+ -(下划线)在emacs + ESS中.
如果你喜欢写=
来<-
,但要使用公开发布的代码比较常见的赋值符号(CRAN上,例如),那么你可以使用的一个tidy_*
功能,在formatR
包自动替换=
用<-
.
library(formatR) tidy_source(text = "x=1:5", arrow = TRUE) ## x <- 1:5
"为什么会x <- y = 5
抛出错误而不是错误x <- y <- 5
?" 这个问题的答案.是"这取决于解析器中包含的魔力".R的语法包含许多含糊不清的案例,必须以某种方式解决.解析器选择取决于是否解决以不同的顺序的表达的比特=
或<-
使用.
要了解发生的情况,您需要知道该任务以静默方式返回已分配的值.例如,您可以通过显式打印更清楚地看到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)
这是因为=
优先级低于帮助页面<-
上显示的优先级?Syntax
.
谷歌的R风格指南通过禁止分配"="来简化问题.不错的选择.
https://google.github.io/styleguide/Rguide.xml
R手册详细介绍了所有5个赋值运算符.
http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html
赋值运算符
=
和<-
R 之间有什么区别?
如您的示例所示,=
并且<-
具有稍微不同的运算符优先级(这决定了它们在同一表达式中混合时的评估顺序).实际上,?Syntax
在R中给出了以下运算符优先级表,从最高到最低:
… ‘-> ->>’ rightwards assignment ‘<- <<-’ assignment (right to left) ‘=’ assignment (right to left) …
但这是唯一的区别吗?
既然你在询问赋值运算符:是的,这是唯一的区别.但是,如果不相信你会被原谅.即使R文件?assignOps
声称存在更多差异:
运算符
<-
可以在任何地方使用,而运算符=
只允许在顶层(例如,在命令提示符下键入的完整表达式中)或作为支撑表达式列表中的子表达式之一.
我们不要过分夸大它:R文档(巧妙地)错误 [ 1 ].这很容易显示:我们只需要找到一个=
运算符的反例,它不是(a)在顶层,也不是(b)在表达式(即{…; …}
)的支撑列表中的子表达式.- 无需再费周折:
x # Error: object 'x' not found sum((x = 1), 2) # [1] 3 x # [1] 1
显然,我们在=
上下文(a)和(b)之外执行了一项任务.那么,为什么几十年来核心R语言功能的文档出错呢?
这是因为在R的语法中,符号=
有两个不同的含义,这些含义经常混淆:
第一个含义是作为赋值运算符.这是我们到目前为止所讨论的全部内容.
第二个含义不是运算符,而是一个语法标记,表示在函数调用中传递的命名参数.与=
运算符不同,它在运行时不执行任何操作,它只是更改表达式的解析方式.
让我们来看看.
在一般形式的任何代码中......
‹function_name›(‹argname› = ‹value›, …) ‹function_name›(‹args›, ‹argname› = ‹value›, …)
... =
是定义命名参数传递的标记:它不是赋值运算符.此外,在某些句法语境中=
完全被禁止:
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代码库的大部分内容中都是普遍存在的模式.
John Chambers的原始解释,R文档可能基于此,实际上解释了这一点:
[
=
赋值]只允许在语法中的两个位置:在顶层(作为完整的程序或用户类型的表达式); 当与周围的逻辑结构隔离时,通过括号或一对额外的括号.
坦白:我早先撒了谎.还有是在之间的一个额外的差异=
和<-
经营者:他们调用不同的功能.默认情况下,这些函数执行相同的操作,但您可以单独覆盖它们中的任何一个以更改行为.相比之下,<-
和->
(左到右分配),虽然语法不同,总是调用相同的功能.覆盖一个也会覆盖另一个.知道这一点很少实用,但它可以用于一些有趣的恶作剧.
x = y = 5
相当于x = (y = 5)
,因为赋值运算符"组"从右到左,有效.含义:分配5 y
,留下数字5; 然后将该5分配给x
.
这不一样(x = y) = 5
,哪个不行!含义:赋值y
to x
,留下值y
; 然后分配5,嗯......,到底是什么?
当你混合不同类型的赋值运算符时,<-
绑定比紧=
.所以x = y <- 5
被解释为x = (y <- 5)
,这是有道理的情况.
不幸的是,x <- y = 5
被解释为(x <- y) = 5
,这是不起作用的情况!
请参阅?Syntax
和?assignOps
查看优先级(绑定)和分组规则.
根据John Chambers的说法,操作员=
只允许在"顶层",这意味着它不允许在控制结构中使用if
,使下面的编程错误成为非法.
> if(x = 0) 1 else x Error: syntax error
正如他所写的那样,"在控制表达式中不允许新的赋值形式[=]避免了编程错误(例如上面的例子),这些错误更可能与运算符相等而不是其他S赋值."
你可以设法做到这一点,如果它"与周围的逻辑结构隔离,通过括号或一对额外的括号",那么if ((x = 0)) 1 else x
就可以了.
请参阅http://developer.r-project.org/equalAssign.html
操作员<-
并=
分配到评估它们的环境中.运算符<-
可以在任何地方使用,而运算符=
只允许在顶层(例如,在命令提示符下键入的完整表达式中)或作为支撑表达式列表中的子表达式之一.
这也可以增加对这两个运算符之间差异的理解:
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