在R中,继承可以通过以下方式扩展基于列表的类来实现:假设lmo
是lm
从线性模型拟合获得的类的对象.该课程可以简单地扩展为:
x <- rnorm(1000)
y <- rexp(1000)
lmo <- lm(x~y)
lmo$addition <- "some more information"
class(lmo) <- c("lmext","lm")
Run Code Online (Sandbox Code Playgroud)
我仍然可以使用所有方法summary.lm
,lm
但也定义了自定义方法.显然,在很多情况下,您希望只有最少的添加,并且仍然希望能够使用父类中的所有方法.
为不基于时间序列等列表的类添加其他属性和实现方法继承的最佳方法是什么?这是我能想象的:
ts1 <- ts(rnorm(100),start = c(1990,1),frequency = 4)
attr(ts1,"additional") <- "some more information"
class(ts1) <- c("tsext","ts")
print.tsext <-
# some method that uses the original print method for ts, plus extracts
# the additional information
Run Code Online (Sandbox Code Playgroud)
这是一个很好的方法来实现类似的运算符+
仍然可以工作,而无需重新定义新类的一切?还有更好的东西吗?有没有办法保留额外的类/属性,例如在不重新定义所有基本运算符的情况下相互添加两个系列?
这是基本功能丢弃其他S3类的问题:
> foo=1:10
> class(foo)
[1] "integer"
> class(foo)=c("thing","integer")
> class(foo[1:4])
[1] "integer"
Run Code Online (Sandbox Code Playgroud)
但是如何Date
绕过这个?
> dv = as.Date(c("2013-01-01","2013-02-02","2013-02-02","2013-02-06"))
> class(dv)
[1] "Date"
> class(dv[2:3])
[1] "Date"
Run Code Online (Sandbox Code Playgroud)
通过重新定义[
为Date
类课程:
> get("[.Date")
function (x, ..., drop = TRUE)
{
cl <- oldClass(x)
class(x) <- NULL
val <- NextMethod("[")
class(val) <- cl
val
}
Run Code Online (Sandbox Code Playgroud)
你可能会注意到这个方法Date
在它的代码中根本没有提到- 它只是获取旧类,调用默认的下标方法,然后重新分配原始类.很明显为什么这不是默认行为是一个谜,但它确实意味着如果你想基于向量创建一个新类,你可以只将这个函数复制为你的新子集方法.
这是我知道在R中创建子类的问题的最简单的例子.这个答案的其余部分将显示更多的危险,我将尽量不要在这个过程中得到太多的暴力.我认为这与你的问题有关.
但遗憾的是,非基类在R代码中被滥用了很多,你最终还是必须编写一些其他相当"通用"的方法来使你的类工作:
> d = data.frame(f=foo,x=1:10)
Error in as.data.frame.default(x[[i]], optional = TRUE) :
cannot coerce class ""thing"" to a data.frame
Run Code Online (Sandbox Code Playgroud)
所以现在你必须写as.data.frame.thing
,幸运的是可以像as.data.frame.Date
> as.data.frame.thing = as.data.frame.Date
> d = data.frame(f=foo,x=1:10)
> d
Run Code Online (Sandbox Code Playgroud)
很好,所以现在你已经thing
在数据框中得到了你的课程.
然后有一天你会尝试dplyr
在一个数据框中使用你的类的向量做一些事情,你得到吐口水:
> d %.% group_by(f) %.% summarise(m=mean(x))
Error in eval(expr, envir, enclos) : column 'f' has unsupported type
Run Code Online (Sandbox Code Playgroud)
但dplyr
与Date
对象一起工作对吗?这是因为在C++代码的深处,它会检查Date
类型.此时你绝望了.
这些只是编写从现有类继承的S3类的一些缺陷.基本上,东西犯规只是工作,至少不是如果您在另一种语言中OOP的经验,你可能期望的那样.