R:通过引用传递
你能通过参考与“R”? 例如,在以下代码中:
setClass("MyClass", representation( name="character" )) instance1 <-new("MyClass",name="Hello1") instance2 <-new("MyClass",name="Hello2") array = c(instance1,instance2) instance1 array instance1@name="World!" instance1 array
输出是
> instance1 An object of class “MyClass” Slot "name": [1] "World!" > array [[1]] An object of class “MyClass” Slot "name": [1] "Hello1" [[2]] An object of class “MyClass” Slot "name": [1] "Hello2"
但我希望是的
> instance1 An object of class “MyClass” Slot "name": [1] "World!" > array [[1]] An object of class “MyClass” Slot "name": [1] "World!" [[2]] An object of class “MyClass” Slot "name": [1] "Hello2"
可能吗 ?
谢谢
皮埃尔
没有 。
赋值语句中的对象是不可变的。 R将复制对象不只是参考。
> v = matrix(1:12, nrow=4) > v [,1] [,2] [,3] [1,] 1 5 9 [2,] 2 6 10 [3,] 3 7 11 [4,] 4 8 12 > v1 = v > v1[,1] # fetch the first column [1] 1 2 3 4
( 条件是 :对于R 原语 ,例如向量,matrix,上面的陈述是正确的),也是对于函数 ; 我不能肯定地说,对于所有的 R对象,只是大部分R对象,以及绝大多数最常用的对象, 都是如此。)
如果你不喜欢这种行为,你可以在R包的帮助下退出。 例如,有一个名为R.oo的R包,它允许你模仿引用行为; R.oo在CRAN上可用。
请注意,如果您希望仅使用传递引用来避免复制未修改对象的性能影响(在其他语言中常用引用常见),R会自动执行此操作:
n <- 10^7 bigdf <- data.frame( x=runif(n), y=rnorm(n), z=rt(n,5) ) myfunc <- function(dat) invisible(with( dat, x^2+mean(y)+sqrt(exp(z)) )) myfunc2 <- function(dat) { x <- with( dat, x^2+mean(y)+sqrt(exp(z)) ) invisible(x) } myfunc3 <- function(dat) { dat[1,1] <- 0 invisible( with( dat, x^2+mean(y)+sqrt(exp(z)) ) ) } tracemem(bigdf) > myfunc(bigdf) > # nothing copied > myfunc2(bigdf) > # nothing copied! > myfunc3(bigdf) tracemem[0x6e430228 -> 0x6b75fca0]: myfunc3 tracemem[0x6b75fca0 -> 0x6e4306f0]: [<-.data.frame [<- myfunc3 tracemem[0x6e4306f0 -> 0x6e4304f8]: [<-.data.frame [<- myfunc3 > > library(microbenchmark) > microbenchmark(myfunc(bigdf), myfunc2(bigdf), myfunc3(bigdf), times=5) Unit: milliseconds expr min lq median uq max 1 myfunc2(bigdf) 617.8176 641.7673 644.3764 683.6099 698.1078 2 myfunc3(bigdf) 1052.1128 1134.0822 1196.2832 1202.5492 1206.5925 3 myfunc(bigdf) 598.9407 622.9457 627.9598 642.2727 654.8786
通过引用可以用于environment
。 您可以尝试使用它们:基本上每当创build一个对象时,都需要创build一个环境插槽。 但我认为这很麻烦。 看看指针并通过引用R和S4中的引用传递。
正如前面所指出的,这可以通过使用class级environment
对象来完成。 build立在使用environment
的基础上的正式方法。 它被称为参考类 ,使事情真的很容易。 检查?setRefClass
主要条目帮助页面的?setRefClass
。 它还描述了如何使用引用类的forms化方法。
例
setRefClass("MyClass", fields=list( name="character" ) ) instance1 <- new("MyClass",name="Hello1") instance2 <- new("MyClass",name="Hello2") array = c(instance1,instance2) instance1$name <- "World!"
产量
> instance1 Reference class object of class "MyClass" Field "name": [1] "World!" > array [[1]] Reference class object of class "MyClass" Field "name": [1] "World!" [[2]] Reference class object of class "MyClass" Field "name": [1] "Hello2"
实际上, R.oo包通过使用环境来模拟传递引用行为。
R现在有一个库,允许你使用引用做OOP。 请参阅作为方法包的一部分的ReferenceClasses 。
除了这里其他的答案,通过引用( environment
对象和引用类)实际传递你的对象,如果你纯粹的兴趣在于引用的语法方便(即你不介意你的数据在里面复制),您可以通过在返回时将最终值分配回外部variables来模拟:
byRef <- function(..., envir=parent.frame(), inherits=TRUE) { cl <- match.call(expand.dots = TRUE) cl[c(1, match(c("envir", "inherits"), names(cl), 0L))] <- NULL for (x in as.list(cl)) { s <- substitute(x) sx <- do.call(substitute, list(s), envir=envir) dx <- deparse(sx) expr <- substitute(assign(dx, s, envir=parent.frame(), inherits=inherits)) do.call(on.exit, list(expr, add=TRUE), envir=envir) } }
然后我们可以声明“引用参考”的参数:
f <- function(z1, z2, z3) { byRef(z1, z3) z1 <- z1 + 1 z2 <- z2 + 2 z3 <- z3 + 3 c(z1, z2, z3) } x1 <- 10 x2 <- 20 x3 <- 30 # Values inside: print(f(x1, x2, x3)) # [1] 11 22 33 # Values outside: print(c(x1, x2, x3)) # [1] 11 20 33
请注意,如果您通过外部名称( x1
, x3
)在函数内部的任何位置访问“by-reference”variables,则会从外部获取尚未修改的值。 另外,这个实现只处理简单的variables名作为参数,所以像f(x[1], ...)
这样的索引参数将不起作用(尽pipe你可以通过一些更复杂的expression式操作来实现,以避开有限的assign
)。
正如其他人所说,S4class是不可能的。 但是R现在提供了R6库的可能性,称为引用类。 见官方文档
除了其他的build议之外,还可以编写C / C ++函数,引用参数并在原地工作,并在R中直接调用它们,这要归功于Rcpp
(等等)。 特别参见这个答案 。