参考:https://www.cnblogs.com/loca/p/4301344.html

主要还是这三兄弟:<- , =, <<-

1. = 和 <-

R语言中,<- 与 = 这两个赋值运算符最主要的区别在于两者的作用域不同。大家可以从下面的例子感受一下。

  1. > rm(x) ## 如果变量 x 存在的话,删除此变量
  2. > mean(x = 1:10)
  3. [1] 5.5
  4. > x
  5. Error: object 'x' not found

在以上范例里,变量 x 是在函数的作用域里进行声明的,所以它只存在于此函数中,一旦运算完成便“消失”。

而如果是<-符号:

  1. > mean(x <- 1:10)
  2. [1] 5.5
  3. > x
  4. [1] 1 2 3 4 5 6 7 8 9 10

ps:至于R 使用<- 太麻烦怎么办,R 提供了快捷键 alt + - 输入。

2. <- 赋值成立条件

上述语句的处理是“将 1:10 赋值给 x , 然后计算 x 的均值。” 吗?在某些语言里,计算机的确是如此处理的,比如说 C 。

  1. > a <- 1
  2. > f <- function(a) return(TRUE)
  3. > f <- f(a <- a + 1); a
  4. [1] TRUE
  5. [1] 1

可见,在R 中并非如此。a 的值并没有改变,在 R 中,在参数中进行赋值的变量只有函数内容调用其时才会发生改变,这其实也是R “懒惰求值”的特性,只有用到某个形式变量的值才求出其对应实参的值。只有使用到a 时,才会求出a 实参结果 a+1,并把其赋值给a,否则a 还是a。

下面的代码更加直观一些:

  1. > a <- 1
  2. > f <- function(a) {
  3. + if(runif(1)>0.5) TRUE
  4. + else a
  5. + }
  6. > f(a <- a+1);a
  7. [1] TRUE
  8. [1] 1
  9. > f(a <- a+1);a
  10. [1] TRUE
  11. [1] 1
  12. > f(a <- a+1);a
  13. [1] TRUE
  14. [1] 1
  15. > f(a <- a+1);a
  16. [1] 2
  17. > f(a <- a+1);a
  18. [1] TRUE
  19. [1] 2
  20. > f(a <- a+1);a
  21. [1] 3

上述代码中,向函数 f() 传递传递参数 a <- a + 1 后,只有在随机数 runif(1) 小于0.5的时候,a 的值才会改变,即执行+1操作。否则传递TRUE值。因此,因为随机数 runif(1) 的随机性,每次调用函数 f()后 a 的值是不确定的。

ps:这样操作的代码可读性可见一斑,如果真的要赋值,为什么不在函数外部呢?如果要传递参数,用 = 再传递不就好了。函数参数弄那么复杂也是太无聊了了吧。

3. <<- 与 ->

刚刚学习R 的时候,我也曾经抱怨,为何不像py 或者其他语言一样,直接 = 大一统不就好了。

但其实,这个赋值号的意义本身是很清晰的。它是有方向的。

箭头的指向,比如 <-,也就是右边指向左边,表示的便是将右边的值赋值给左边,如果你喜欢,用 -> 甚至都是可以的。

  1. > 5 -> s
  2. > s
  3. [1] 5

在 R 语言中,处在某一个环境层的代码都拥有读入上一环境层的变量的权限,但相反地,若只通过标准的赋值运算符 <- ,是无法向上一环境层写入变量的。若想在上一环境层进行赋值行为,即向上一层次写入变量,则需要用到 <<- (superassignment)运算符啦~

比如在闭包中使用超赋值:

  1. f.gen <- function(){
  2. runTimes <- 0
  3. function(){
  4. runTimes <<- runTimes + 1
  5. print(runTimes)
  6. }
  7. }
  8. f <- f.gen()
  9. f()

此时每调用一次函数f,其内部的次数结果都会向上复制给外部的runTimes。

需要注意的是,一般说来, <<- 多用于在顶层环境中写入变量。然而需要注意的是,以 <<- 执行赋值时,会一直向上直至顶层进行变量查找。若在查找过程中寻找到该名称的变量,就会进行赋值操作。否则,将在顶层环境中创建变量并赋值。

(即如果想在多层函数的内部使用 <<- 改变全局环境中内容的话,需要注意中间函数是否存在相同名称的变量)

比如:

  1. > glob <- function(){
  2. + d <- 5
  3. + nxt1 <- function(){d <<- e + 1}
  4. + e <- 2
  5. + nxt1()
  6. + d
  7. + }
  8. > glob()
  9. [1] 3
  10. > d
  11. Error: object 'd' not found
  12. ## 对比以下
  13. > glob <- function(){
  14. >
  15. + ##区别在这里,少了一行' d <- 5'
  16. +
  17. + nxt1 <- function(){d <<- e + 1}
  18. + e <- 2
  19. + nxt1()
  20. + d
  21. + }
  22. > glob()
  23. [1] 3
  24. > d
  25. [1] 3

总结

  • 赋值使用 <-
  • 传参数 =
  • 上一环境赋值 <<-