代码之家  ›  专栏  ›  技术社区  ›  Pierre

你能在R里通过参考号吗?

  •  56
  • Pierre  · 技术社区  · 16 年前

    你能用“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"
    

    有可能吗?

    9 回复  |  直到 8 年前
        1
  •  52
  •   krlmlr    14 年前

    不 .

    赋值语句中的对象是不可变的。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,上述语句是正确的 原语 ,例如向量、矩阵),以及 功能 ;我不能肯定这是否是真的 全部的 r对象——大多数对象,以及大多数最常用的对象。)

    如果你不喜欢这种行为,你可以在r包的帮助下选择退出。例如,有一个名为 小精灵 它允许您模拟按引用传递行为;r.oo在 CRAN .

        2
  •  37
  •   Ari B. Friedman    14 年前

    请注意,如果希望使用按引用传递来避免复制未修改的对象(这在具有常量引用的其他语言中很常见),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
    
        3
  •  17
  •   Rappster    12 年前

    如前所述,这可以通过使用类的对象来实现 environment . 在使用 环境 它被称为 参考类 让事情变得简单。检查 ?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"
    
        4
  •  16
  •   smci    8 年前

    可以通过引用传递 environment 基本上,当你创建一个对象时,你也需要创建一个环境槽。但我觉得很麻烦。看一看 Pass by reference for S4. 和 Pointers and passing by reference in R

        5
  •  5
  •   Kyle Brandt    14 年前

    r现在确实有一个库,允许您使用引用进行oop。见 ReferenceClasses 它是methods包的一部分。

        6
  •  4
  •   user350780    15 年前

    事实上 小精灵 包使用环境模拟按引用传递行为。

        7
  •  3
  •   Jules Sam. Randolph    10 年前

    正如其他人所说,这是不可能的S4类。但是r现在提供了 R6 图书馆,叫 参考 类。见 official documentation

        8
  •  2
  •   codeola    12 年前

    除了这里的其他答案 通过 你的参照物( 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], ...) 将无法工作(尽管您可能可以通过更复杂的表达式操作来实现它,以避开有限的 assign )

        9
  •  1
  •   Hugo Raguet    9 年前

    在其他建议的基础上,还可以通过引用和工作来编写C/C++函数。 就位 ,并直接在r中呼叫他们,感谢 Rcpp (除其他外)。 具体见 this answer .

    推荐文章