为什么函数t为类设置为“test”的对象返回t.test?

时间:2016-03-12 20:43:43

标签: r

我正在阅读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来自哪里?

1 个答案:

答案 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()会明确过滤掉已知不是方法的函数。另一方面,方法调度只是查找具有适当名称的函数。