R S4类继承的方法不会在第一次调用时加载,而是在第二次

时间:2017-11-20 14:05:01

标签: r methods s4

我想学习R中的OO编程,作为练习,我要编写一小组用于读写Fortran名单的函数和方法。我是一个完整的菜鸟,所以请对下面的例子表示友好(你可以复制粘贴)。

我有以下类定义:

setClass("NamelistValue")
setClassUnion("NamelistValue", c("numeric", "character"))
setClass("Namelist",
        representation(group = "character", variable = "character", value = "NamelistValue", comment = "character", file="character"),
        prototype(group = NA_character_, variable = NA_character_, value = NA_real_, comment = NA_character_, file = NA_character_)
        )

例如,这些替换数据的方法:

setMethod("[<-", c("Namelist", "character", "character", "NamelistValue"),
    function (x, i, j, ..., value) {
        if (length(i) > 1 | length(j) > 1) stop("Cannot subset with more than one index")
        l <- which(x@group==i)
        v <- which(x@variable[l]==j)
        vals <- x@value
        vals[l][v] <- value
        initialize(x, group=x@group, variable=x@variable, value=vals, comment=x@comment, file="<None>")
    }
)

setMethod("[<-", c("Namelist", "missing", "character", "NamelistValue"),
    function (x, i=NULL, j, ..., value) {
        if (length(i) > 1 || length(j) > 1) stop("Cannot subset with more than one index")
        v <- which(x@variable==j)
        vals <- x@value
        vals[v] <- value
        initialize(x, group=x@group, variable=x@variable, value=vals, comment=x@comment, file="<None>")
    }
)

现在我设置了一个对象:

a <- new("Namelist", group="pippo", variable="ears", value=2, comment="Hi!")

让我们看一下使用showMethods(class = "Namelist")的方法,这里是输出:

Function: [<- (package base)
x="Namelist", i="character", j="character", value="NamelistValue"
x="Namelist", i="missing", j="character", value="NamelistValue"

Function: initialize (package methods)
.Object="Namelist"
    (inherited from: .Object="ANY")

看起来很好。现在我尝试用a[,"ears"] <- 4替换某些值,命令失败

Error in `[<-`(`*tmp*`, , "ears", value = 4) : 
  argument "i" is missing, with no default

但是,如果我再次尝试相同的命令再次成功 ...我从showMethods(class = "Namelist")看到已经创建/继承了一些其他方法:

Function: [<- (package base)
x="Namelist", i="character", j="character", value="NamelistValue"
x="Namelist", i="missing", j="character", value="NamelistValue"
x="Namelist", i="missing", j="character", value="numeric"
    (inherited from: x="Namelist", i="missing", j="character", value="NamelistValue")

Function: initialize (package methods)
.Object="Namelist"
    (inherited from: .Object="ANY")

这是为什么?为什么它首先不起作用,但只在第二次尝试?我该如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

(我没有R的源代码,对于编辑此代码的人很高兴。[<-是内部的,所以我看不到它的代码只是它的文档。)

内部泛型在调度方法之前会对它们自己进行一些检查,这包括评估签名中的所有参数(包括i)。因此,您的第一次调用失败,因为i没有默认值可以依赖(该方法尚未注册)。但是,默认方法足以注册S4方法,因此当退出调用时,方法已经注册。

通过在第一次通话之前和之后查看showMethods("[<-")可以看出这一点。之后,尽管有错误,但它显示了继承的方法。

第二个调用有一个预先注册的方法,所谓的直接因为签名完全匹配。这看到了NULL的默认值i并根据需要使用了它,而[<-的通用名称从未被调用过,因此我们不再看到错误。

我认为selectMethod可能会以类似的方式注册方法而没有错误,但显然它没有。可能的解决方法可能是:

  • NamelistValue(yuck!)
  • 的每个子类编写单独的方法
  • 使用显式""而不是缺少参数:a["","ears"] <- ... ---这不会导致错误,副作用最小并注册必要的方法。麻烦的是你必须分别对字符和数字这样做:

    a [“”,“ear”]&lt; - 4 a [“”,“ear”]&lt; - “ear!”

这应该涵盖所有继承的方法,但我很欣赏它并不理想......