我正在阅读Hadley Wickham的书籍Advanced R,特别是OO fied指南(http://adv-r.had.co.nz/OO-essentials.html)。该章的第一个练习如下:
读取t()和t.test()的源代码,并确认t.test()是S3泛型而不是S3方法。如果使用类测试创建对象并使用它调用t(),会发生什么?
如果我正确理解了这一章,我们可以确认t()和t.test()是通用的,因为它们在源代码中使用了UseMethod()函数。 methods(t)返回t.data.frame,t.default和t.ts *作为函数t()的方法。那么,如果两者都是S3泛型并且t没有t.test方法,那么下面的代码是否返回t检验?
a <- structure(1:4, class = "test")
t(a)
我的预测是t会使用类“test”的默认方法而t.default(a)会根据我的假设进行转置。那时t.test来自哪里?
答案 0 :(得分:6)
如果您运行t(a)
,其中a
是您的班级test
的对象,则会调用UseMethod("t")
。这将检查您向t()
提供的第一个参数的类是什么。该班级为test
,R现在为
寻找函数t.test()
。由于存在t.test()
,因此运行t.test(a)
。这被称为&#34;方法调度&#34;。
只有当t.test()
不存在时,R才会求助于t.default()
。实际上,您可以通过在运行stats
之前分离t(a)
包来实现这一点:
a <- structure(1:4, class = "test")
detach("package:stats")
t(a)
## [,1] [,2] [,3] [,4]
## [1,] 1 2 3 4
## attr(,"class")
## [1] "test"
现在的问题是,当您运行t.test
时,为什么methods("t")
未包含在列表中。当您查看methods()
的源代码时,您会注意到它调用了.S3methods()
。此函数编译t
的所有方法的名称。但是,在某些时候,它会删除S3MethodsStopList
中包含的函数名称:
info <- info[grep(name, row.names(info)), ]
info <- info[!row.names(info) %in% S3MethodsStopList,
]
(如果我在RStudio中运行编辑(.S3方法),这些是第47和48行。)
之前定义了 S3MethodsStopList
(第15行):
S3MethodsStopList <- tools:::.make_S3_methods_stop_list(NULL)
函数tools:::.make_S3_methods_stop_list()
似乎没有被记录,但它似乎只返回一个包含点的函数名的硬编码列表,但实际上不是方法。 t.test()
就是其中之一:
grep("^t\\.", tools:::.make_S3_methods_stop_list(NULL), value = TRUE)
## Hmisc6 calibrator mosaic mratios1
## "t.test.cluster" "t.fun" "t.test" "t.test.ration"
## mratios2 mratios3 stats6
## "t.test.ratio.default" "t.test.ratio.formula"
简而言之,methods()
会明确过滤掉已知不是方法的函数。另一方面,方法调度只是查找具有适当名称的函数。