类似于S4类的这个主题,我想知道S3类的解决方法和冲突预防。
让我举个例子。我创建了两个包:pkga和pkgb。它们碰巧都有一个S3类构造函数,返回一个类名称相同的对象myclass
#' @export
myclass_instance <- function() {
structure(list(name = "pkga"), class = c("myclass"))
}
#' @export
whatever <- function(obj) {
UseMethod("whatever", obj)
}
#' @export
whatever.default <- function(obj) {
print("pkga::whatever.default")
}
#' @export
whatever.myclass <- function(obj) {
print("pkga::whatever.myclass")
}
和pkgb
#' @export
myclass_instance <- function() {
structure(list(name = "pkgb"), class = c("myclass"))
}
#' @export
whatever <- function(obj) {
UseMethod("whatever", obj)
}
#' @export
whatever.default <- function(obj) {
print("pkgb::whatever.default")
}
#' @export
whatever.myclass <- function(obj) {
print("pkgb::whatever.myclass")
}
现在,如果我安装了两个包,并尝试以下操作:
> aobj<-pkga::myclass_instance()
> pkga::whatever(aobj)
[1] "pkga::whatever.myclass"
> pkga::whatever(3)
[1] "pkga::whatever.default"
这些都是正确的。但是,如果我从pkgb创建一个对象,然后将其传递给pkga::whatever
,它将不会像我期望的那样应用默认值(它们是两个完全不相关的类,恰好具有相同的名称),因为解析只对名称
> bobj<-pkgb::myclass_instance()
> pkga::whatever(bobj)
[1] "pkga::whatever.myclass"
如果两个不相关的库碰巧具有相同的类名,并且泛型名碰巧冲突,则会产生奇怪的效果。虽然这是一种罕见且不太可能发生的情况,但从正式的角度来看,我一点也不喜欢它,所以我想知道是否有一种方法可以防止这种情况的发生,比在类名前加上包名更好,例如
#' @export
myclass_instance <- function() {
structure(list(name = "pkga"), class = c("pkga::myclass"))
}
#' @export
whatever <- function(obj) {
UseMethod("whatever", obj)
}
#' @export
whatever.default <- function(obj) {
print("pkga::whatever.default")
}
#' @export
`whatever.pkga::myclass` <- function(obj) {
print("pkga::whatever.myclass")
}
和类似的pkgb。
包a和包b使用不同的命名空间。S3的构建是非正式的,所以解决这个问题的唯一方法是使用包名前缀(即pkg::whatever
)。
解决这个问题需要一定程度的特异性,这是R中所缺乏的(除了显式前缀)。根据R Packages的这一章,这是一个已知的现象。