提问人:csgillespie 提问时间:11/16/2009 最后编辑:user438383csgillespie 更新时间:1/14/2023 访问量:363049
“=”和“<-”赋值运算符有什么区别?
What are the differences between "=" and "<-" assignment operators?
问:
赋值运算符和 R 中的运算符有什么区别?=
<-
我知道运算符略有不同,如本例所示
x <- y <- 5
x = y = 5
x = y <- 5
x <- y = 5
# Error in (x <- y) = 5 : could not find function "<-<-"
但这是唯一的区别吗?
答:
运算符并分配到他们所处的环境中 被评估。运算符可以在任何地方使用,而 operator
=
只允许在顶层(例如,在 在命令提示符下键入的完整表达式)或作为 带支撑的表达式列表中的子表达式。<-
=
<-
评论
x <- 42
if (x <- 42) {}
1 + (x = 2)
function() x = 1
repeat x = 1
if (TRUE) x = 1
当您使用赋值运算符在函数调用中设置参数值时,它们之间的区别会更加明显。例如:
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 都具有键盘快捷方式,以便于键入。 + 在 Architect 中,在 RStudio 中 +(在 macOS 下为 +),在 emacs+ESS 中为 +(下划线)。<-
Ctrl=Alt-Option-Shift-
如果您更喜欢写入,但希望对公开发布的代码(例如在 CRAN 上)使用更常见的赋值符号,则可以使用包中的 tidy_*
函数之一自动替换为 。=
<-
formatR
=
<-
library(formatR)
tidy_source(text = "x=1:5", arrow = TRUE)
## x <- 1:5
“为什么会抛出错误,但不会?”这个问题的答案是“这要归结为解析器中包含的魔力”。R 的语法包含许多模棱两可的情况,必须以一种或另一种方式解决。分析器选择以不同的顺序解析表达式的位,具体取决于是否使用了 或。x <- y = 5
x <- y <- 5
=
<-
若要了解所发生的情况,您需要知道赋值以静默方式返回已赋值。例如,您可以通过显式打印更清楚地看到这一点。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)
这是因为优先级低于 ,如 上所示?语法
帮助页面。=
<-
评论
x <- x = 5
`<-<-`(x, y = 5, value = 5)
tmp <- x; x <- `<-<-`(tmp, y = 5, value = 5)
=
x
...
=
=
f(x = 1)
call("f", 1)
x = 1
call("=", "x", 1)
Google 的 R 风格指南通过禁止使用“=”进行分配来简化问题。不是一个糟糕的选择。
https://google.github.io/styleguide/Rguide.xml
R 手册详细介绍了所有 5 个赋值运算符。
http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html
评论
TRUE
x
-y
if (x<-y)
FALSE
y=0
<-
=
=
<<-
<-
根据 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
x = y = 5
等价于 ,因为赋值运算符从右到左“分组”,这有效。意思是:将 5 赋值给 ,留下数字 5;然后将该 5 分配给 .x = (y = 5)
y
x
这与 不同,这是行不通的!含义:将 的值赋给 ,留下 的值;然后将 5 分配给,嗯......,到底是什么?(x = y) = 5
y
x
y
混合使用不同种类的赋值运算符时,绑定比 更紧密。所以被解释为 ,这是有意义的情况。<-
=
x = y <- 5
x = (y <- 5)
不幸的是,被解释为 ,这是行不通的!x <- y = 5
(x <- y) = 5
有关优先级(绑定)和分组规则,请参阅 和。?Syntax
?assignOps
评论
这也可以增加对这两个运算符之间差异的理解:
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
赋值运算符和 R 中的运算符有什么区别?
=
<-
如示例所示,并且运算符优先级略有不同(这决定了它们在同一表达式中混合时的计算顺序)。事实上,?
R 中的语法给出了以下运算符优先级表,从高到低:=
<-
… ‘-> ->>’ rightwards assignment ‘<- <<-’ assignment (right to left) ‘=’ assignment (right to left) …
但这是唯一的区别吗?
既然你问的是赋值运算符:是的,这是唯一的区别。但是,如果您不这么认为,那将是可以原谅的。甚至 ?assignOps
的 R 文档也声称存在更多差异:
操作员可以在任何地方使用, 而运算符只允许在顶层(例如, 在命令提示符下键入的完整表达式中)或作为一个 的子表达式。
<-
=
我们不要说得太细:R 文档是错误的。这很容易说明:我们只需要找到一个运算符的反例,该运算符不是 (a) 在顶层,也不是 (b) 表达式列表(即 )。— 事不宜迟:=
{…; …}
x
# Error: object 'x' not found
sum((x = 1), 2)
# [1] 3
x
# [1] 1
显然,我们已经在上下文 (a) 和 (b) 之外使用了 ,执行了一项任务。那么,为什么核心 R 语言功能的文档几十年来一直是错误的呢?=
这是因为在 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›) …
其中任何一个都会引发错误“意外的'='在‹bla›中”。
在任何其他上下文中,引用赋值运算符调用。特别是,只需在子表达式周围加上括号即可使上述任何 (a) 有效,并且 (b) 赋值。例如,以下执行赋值:=
median((x = 1 : 10))
而且:
if (! (nf = length(from))) return()
现在你可能会反对这样的代码是残酷的(你可能是对的)。但是我从 base::file.copy
函数中获取了这段代码(将 <-
替换为 =
)——这是许多核心 R 代码库中普遍存在的模式。
John Chambers 的原始解释(R 文档可能基于此)实际上正确地解释了这一点:
[
=
赋值]只允许在语法中的两个地方进行:在顶层(作为完整的程序或用户键入的表达式);当与周围的逻辑结构隔离时,通过大括号或一对额外的括号。
总之,默认情况下,运算符和执行相同的操作。但是,它们可以单独覆盖它们中的任何一个以更改其行为。相比之下,and(从左到右赋值)虽然在语法上不同,但总是调用相同的函数。覆盖一个也会覆盖另一个。知道这一点很少实用,但它可以用于一些有趣的恶作剧。<-
=
<-
->
评论
?
=
<-
?
main/gram.y
),正确记录了 的优先级,并且低于 和 。?
=
<-
=
=
=
;
=
我不确定帕特里克·伯恩斯 (Patrick Burns) 的书 R inferno 是否在这里被引用,其中 8.2.26 = 不是 < 的同义词 - 帕特里克说:“当你想设置函数的参数时,你显然不想使用'<-'。该书可在 https://www.burns-stat.com/documents/books/the-r-inferno/
评论
R的过去版本甚至R的前身语言(S语言)之间存在一些差异。但目前,似乎只像任何其他现代语言(python、java)一样使用不会造成任何问题。您可以通过将值传递给某些增强项来实现更多功能,同时还创建全局变量,但它可能具有奇怪/不需要的行为,例如<-
=
=
<-
df <- data.frame(
a = rnorm(10),
b <- rnorm(10)
)
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 ...
强烈推荐!尝试阅读这篇文章,这是试图解释这两者之间区别的最佳文章: 检查 https://colinfay.me/r-assignment/
此外,将 about 视为一个无形返回值的函数。<-
a <- 2
(a <- 2)
#> [1] 2
请参见:https://adv-r.hadley.nz/functions.html
评论
=
<-
=
<-
df <- data.frame(a = rnorm(10), (b = rnorm(10)))
,
=
<-
R
=
(
(b = rnorm(10))
b <- rnorm(10)
(
=
=
(
=
<-
评论
<-
<-