在编写S3方法时如何避免三重冒号(:: :)?

时间:2017-09-01 17:33:51

标签: r class methods plot

我正在编写一个包,我有一个返回data.framemyclass的函数。将它保存为data.frame非常重要,因此我将新类添加到对象中(下面的代码当然没有多大意义,但它仅用于说明):

foo <-  function(x) {
  df <- data.frame(a = x, b = "b", c = 1)
  class(df) <- append(class(df), "myclass")
  return(df)
}

test <- foo(1:3)

现在,我想为这个类创建一个S3方法:

plot.myclass <- function(x, ...) {
  plot(a~b, data = test)
}

问题是,由于testdata.frameplot(test)会从包plot.data.frame调用未导出的函数graphics

我试图通过将另一个(未导出的)函数定义为:

来解决这个问题
plot.data.frame <-  function(x, ...){
  if ("myclass" %in% class(x)) plot.myclass(x, ...)
  else graphics:::plot.data.frame(x, ...)
}

工作正常,但是devtools::check()给了我一个警告,实际上:::的文档说明了

  

在代码中使用:::通常是一个设计错误   相应的对象可能已经内部保持良好状态   原因。如果您有这种感觉,请考虑联系软件包维护人员   只需要检查就可以访问该对象。

解决这个问题的首选方法是什么?

我当然可以(i)摆脱data.frame课程,但正如我所说,我更愿意保留它(ii)只需将plot.data.frame的现有代码复制到最后一个函数的else语句,或者(iii)简单地覆盖原始plot.data.frame而忽略原始功能(绘制数据框) - 其中任何一个似乎都没有比我想象的更优雅有,但我确信有更好的解决方案。

任何见解都将受到赞赏。

1 个答案:

答案 0 :(得分:4)

您希望'myclass'在对象类中的'data.frame'类之前来。这样,调度将首先查找<generic>.myclass,如果找不到<generic>.data.frame类通用的方法,则只查找'myclass'

要实现这一目标,您只需修改这一行

即可
class(df) <- append(class(df), "myclass")

阅读

class(df) <- append(class(df), "myclass", after = 0)

但它同样易于使用

class(df) <- c('myclass', class(df))

对于后者,它非常明确,而append()实际上是向后的,因为你需要 prepend 这个类。

对于更普遍的问题,没有一种方法可以在另一个包的命名空间中导入或使用非导出的方法或函数,而不会在检查包时生成各种警告。假设您不应该直接调用非导出函数(因为该函数不是供用户使用),并且任何尝试这样做都是打包代码的问题。