r - S4 类 : arguments passed to new() don't go into their slots

标签 r new-operator s4 slots

我正在用 S4 类构建 R 包,但在使用 new 时遇到了问题功能。我有一个类(class)叫 Configs

setClass("Configs", 
  slots = list(
    burnin = "numeric",
    chains = "numeric",
    features = "numeric",
    iterations = "numeric",
    mphtol = "numeric",
    samples = "numeric",
    seed = "numeric",
    thin = "numeric",
    verbose = "numeric"
  ),
  prototype = list(
    burnin = 0,
    chains = 2,
    features = 5,
    iterations = 5,
    mphtol = 1e-4,
    samples = 3,
    seed = sample(1e6, 1),
    thin = 0,
    verbose = 0
  )
)

当我将这部分加载到我的全局环境中时,我可以创建一个新的 Configs插槽与默认值不同的对象。
> new("Configs", features = 1000)
An object of class "Configs"
Slot "burnin":
[1] 0

Slot "chains":
[1] 2

Slot "features":
[1] 1000

Slot "iterations":
[1] 5

Slot "mphtol":
[1] 1e-04

Slot "samples":
[1] 3

Slot "seed":
[1] 437211

Slot "thin":
[1] 0

Slot "verbose":
[1] 0

但是,当我安装整个包时,将其加载到新环境中,然后运行 ​​new("Configs", features = 1000) , 我得到一个 features 5. 为什么不new()再把值放在插槽中?

我的包裹通过了 R CMD check没有任何错误、警告或注释。这是我的 session 信息。
> sessionInfo()
R version 3.2.0 (2015-04-16)
Platform: x86_64-unknown-linux-gnu (64-bit)
Running under: CentOS release 6.6 (Final)

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] heterosis_0.0  pracma_1.8.3   MCMCpack_1.3-3 MASS_7.3-40    coda_0.17-1   

loaded via a namespace (and not attached):
[1] tools_3.2.0     grid_3.2.0      lattice_0.20-31

编辑:我明白了,但我仍然不满意。

原来我的initialize功能导致问题。
setMethod("initialize", "Configs", function(.Object, ...){ 
#  .Object = new("Configs", ...)
  validObject(.Object)      
  return(.Object)
})

当我删除它时,new再次将东西放入插槽中。我很高兴我发现了这个问题,但我不想完全删除我的初始化函数。我想要一种方便的方法来调用 validObject 并进行其他错误检查,还有 initialize似乎是一个适当和合适的地方。如果我取消注释注释行,我会得到无限递归。如何在不破坏的情况下创建构造函数 new ?

最佳答案

initialize()是双重目的——初始化和复制构造。提供显式构造函数通常更好(也为用户提供更多信息)

.A = setClass("A", representation(x="numeric"))

A = function(x=numeric(), ...)
    .A(x=x, ...)
validOjbect()当对象创建涉及插槽分配时,由默认 initialize 方法调用,因此无需在您自己的 initialize 方法期间显式调用它(见下文);也许你会有
.A = setClass("A", representation(x="numeric"),
    prototype=prototype(x=NA_integer_))

setValidity("A", function(object) {
    if (length(object@x) != 1L)
        "'x' must be length 1"
    else TRUE
})

A = function(x=NA_integer_, ...)
    ## signature is informative -- 'x' is integer(1), not just '...'
    ## coercion (e.g., as.integer(), below) and other set-up
    new("A", x=as.integer(x), ...)


> A()
An object of class "A"
Slot "x":
[1] NA

> A(x=1)
An object of class "A"
Slot "x":
[1] 1

> A(x=1:2)
Error in validObject(.Object) : 
  invalid class "A" object: 'x' must be length 1

一个重要的警告是,当没有用户初始化的槽时,validity 方法不会被调用,所以 prototype()必须定义以创建有效对象(使用 validObject(new("A")) 验证这一点。

对于您的问题,有效性函数是进行“其他错误检查”的正确位置。编写正确的初始化方法非常困难,但更接近正确的是
.B = setClass("B",
    representation(x="numeric", y="numeric"),
    prototype=prototype(x=NA_integer_, y=NA_real_))
setMethod("initialize", "B", 
    function(.Object, ..., x=.Object@x, y=.Object@y)
{
    ## pre-processing, then invoke 'next' initialize() method
    ## base initialize() creates the object then calls validObject()
    ## so no need for explicit test of validity
    .Object <- callNextMethod(.Object, ..., x=x, y=y)
    ## post-processing
    .Object
})

这种奇怪的结构允许 initialize()继续充当复制构造函数
> b = new("B", x=1, y=2)    # constructor
> initialize(b, x=2)        # copy-constructor
An object of class "B"
Slot "x":
[1] 2

Slot "y":
[1] 2

这在类继承期间很重要。但是正如你所看到的,这很棘手——最终它真的很艰难,很少值得为获得 initialize() 而付出努力。正确的。

请注意,我们还没有完全履行initialize()的契约(Contract)。 ,
setClass("C", representation(x="numeric", y="numeric"))  # default initialize()

当使用 new() 调用时,它实际上充当复制构造函数
> c = new("C", x=1, y=2)
> new("C", c, x=2)
An object of class "C"
Slot "x":
[1] 2

Slot "y":
[1] 2

与 B 的实现没有复制构造
> b = new("B", x=1, y=2)
> new("B", b, x=2)
An object of class "B"
Slot "x":
[1] 2

Slot "y":
[1] NA

关于r - S4 类 : arguments passed to new() don't go into their slots,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30562141/

相关文章:

image - 缩放 R 图像

R .libPaths() 自动重置

c# - 将参数传递给模板化类型的 C# 泛型 new()

c++ - 重载新运算符 : How the size will be passed?

r - 什么是setReplaceMethod(),它如何工作?

r - 在 R 的循环中将字符串视为对象名称

从列名中删除部分字符串

c++ - 处理使用 new 运算符创建的数组时出现问题

r - `[.` `ReferenceClass` 方法

R S4 插槽作为自定义类列表