70

你可以通过引用传递“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"

可能吗 ?

4

9 回答 9

56

No.

Objects in assignment statements are immutable. R will copy the object not just the reference.

> 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

(proviso: the statement above is true for R primitives, e.g., vectors, matrices), and also for functions; I cannot say for certain whether it's true for all R objects--just most of them, as well as the vast majority of the ones most often used.)

If you don't like this behavior you can opt out of it with the help from an R Package. E.g., there is an R Package called R.oo that allows you to mimic pass-by-reference behavior; R.oo is available on CRAN.

于 2010-04-08T20:43:01.667 回答
48

请注意,如果您希望使用按引用传递只是为了避免复制未修改的对象的性能影响(这在其他具有常量引用的语言中很常见),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
于 2012-08-01T11:27:33.517 回答
29

正如一些人之前指出的,这可以通过使用 class 的对象来完成environment。存在一种建立在使用environments 的正式方法。它被称为参考类,它使您的事情变得非常容易。检查?setRefClass主条目帮助页面。它还描述了如何将形式化方法与引用类一起使用。

例子

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"
于 2012-03-12T13:27:26.527 回答
23

s可以通过引用传递environment。要使用它们,基本上每当你创建一个对象时,你都需要创建一个环境槽。但我认为这很麻烦。看看 S4 的参考传递。指针并在R中通过引用传递

于 2010-04-08T21:24:21.430 回答
6

R does have a library now that allows you to do OOP using references. See ReferenceClasses which is part of the methods package.

于 2012-01-31T02:44:23.740 回答
4

实际上,R.oo包通过使用环境来模拟通过引用的行为。

于 2011-01-05T16:04:07.037 回答
3

正如其他人所说,S4 课程是不可能的。但是 R 现在提供了R6库的可能性,称为引用类。见官方文档

于 2015-11-10T01:20:32.750 回答
2

除了此处实际通过引用传递对象的其他答案(environment对象和引用类)之外,如果您出于语法方便而纯粹对引用调用感兴趣(即,您不介意复制内部的数据),您可以通过在返回时将最终值分配回外部变量来模拟:

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,您将从外部获得它们尚未修改的值。此外,此实现仅将简单的变量名称作为参数处理,因此诸如索引参数之类的参数f(x[1], ...)将不起作用(尽管您可以通过更多涉及的表达式操作来实现它以避开 limited assign)。

于 2014-02-20T07:06:34.393 回答
2

除了其他建议之外,您还可以编写 C/C++ 函数,通过引用获取参数并就地工作,并在 R 中直接调用它们,这要归功于Rcpp(以及其他)。特别看这个答案

于 2017-08-23T14:56:01.780 回答