一、值传递

在R语言中,一切皆为对象,同时在调用函数的时候也采用值传递的方式,即作为参数的对象会被复制,然后将副本传递给函数

例如:

> f<-function(df2){
+   df2$a<-c(1,2,3)
+ }
> df<-data.frame(a=c(4,5,6))
> f(df)
> df
  a
1 4
2 5
3 6

这里将数据框作为参数传递给函数的时候,函数内部的修改将不会影响原对象。这是因为调用f()函数时采用的时值传递的方法;df2中保持的不是指向原始数据df的引用,而是复制数据框df,df2指向的是副本数据框

如果我们想让函数内部的改动影响到函数外部,则需要在函数f()内部用返回值修改语句,然后再将函数的返回值的修改结果赋值给原来的变量

例如:

> f<-function(df2){
+   df2$a<-c(1,2,3)
+   return(df2)
+ }
> df<-data.frame(a=c(4,5,6))
> df<-f(df)
> df
  a
1 1
2 2
3 3

因此我们可以得出结论,除了特殊对象以外,对象状态不会被函数直接修改,无论哪种函数能能保证参数传递的对象不被修改

PS:这一部分我觉得结合C++中指针那一块的内容食用更佳

二、对象不变性

R中的对象通常是不变的,在编程中,值不变意味着数值不能被修改

例如:

> a<-list()
> a$b<-c(1,2,3)

这则代码实际上进行的步骤是先复制a,创建新对象a',然后向对象a'添加属性b,再将c(1,2,3)填充到b,最后让变量名指向a'。

R语言长数据变成宽数据 r语言中变数长度不一致_值传递

而并非在a中直接开辟一个新属性b,让后将c(1,2,3)复制给b

我们利用对象复制追踪函数tracemem()进行查看

> a<-list()
> tracemem(a)
[1] "<000001D6746E3A80>"
> tracemem(a$b<-c(1,2,3))
[1] "<000001D6771B61E8>"

我们可以发现内存地址进行了更改,意味着其进行了复制导致内存地址增加

所以在R语言里使用循环语句是很不明智的,因为会导致内存占用不断增加吃掉太多资源,从而让效率降低,因此我们还是推荐使用向量来代替实现循环语句

例如我们要实现1~1000000全体加1

循环语句

> v<-1:1000000
> for(i in 1:1000000)
+   v[i]<-v[i]+1

执行完毕后会发现内存急速扩大

利用向量

> v<-1:1000000
> v<-v+1

这样会快很多,而且占用资源更低