在@G之后重写。格洛腾迪克的答案
在 Advanced R 中,关于S3 classes,我遇到了以下函数定义:
new_Date <- function(x = double()) {
stopifnot(is.double(x))
structure(x, class = "Date")
}
我认为将double()
设置为默认值是一种强制用户为double
类型输入x
值的方法,但由于函数随后会使用stopifnot
。
阅读@G。 Grothendieck的回答,我知道double()
是 double NA 。这是否意味着double()
的使用仅允许函数使用(空)双精度模式,即使没有提供参数时(而不是抛出 missing参数错误),并且与检查x的类无关吗?
原始问题
我有时会看到将参数默认值定义为空(或定长)类型的函数,例如:
func1 <- function(a = logical(), b = numeric(1)){
if (a){
b
} else {
0
}
}
我知道这可以简化阅读过程,以了解每个参数的类型。但这似乎并不强制参数为这种类型。
func1(a = 4, b = 3)
# 3
func1(a = 4, b = TRUE)
# TRUE
我知道,在该特定示例中,如果将if (a)
更改为if (a == TRUE)
,如果a
不符合逻辑,则会触发错误。但是通常,如果不检查函数体内的参数类型,这种参数定义的用途是什么?
我倾向于使用这种函数定义,但这要重得多:
func2 <- function(a, b){
if (class(a) != 'logical') stop('a must be logical')
if (!(class(b) == 'numeric' & length(b) == 1)) stop(
'b must be numeric(1)'
)
...
}
答案 0 :(得分:2)
假设a
是逻辑NA,那么它仍应返回0,然后尝试执行此操作(或如果a * b
的逻辑NA应该用a
替换正文的第二行)返回NA)。
无论如何,主要要点是以下stopifnot
样式可用于参数检查。
func2 <- function(a, b) {
stopifnot(is.logical(a), is.numeric(b))
isTRUE(a) * b
}
func2(TRUE, 3)
## [1] 3
func2(9, 2)
## Error in func2(9, 2) : is.logical(a) is not TRUE
如果您要自定义错误消息,请使用stopifnot
而不是if (...) stop(...)
,每个参数一个这样的语句。
请注意,可以使用S3调度到基于第一个参数的方法,也可以使用S4调度到给定的签名。如果不存在用于这种签名的方法,则会触发错误。
这是一个S4示例:
setMethod("func3", c("logical", "numeric"), function(a, b) isTRUE(a) * b)
func4(TRUE, 3)
## [1] 3
func4(2, 1)
## Error in UseMethod("func3") :
## no applicable method for 'func4' applied to an object of class "c('double', 'numeric')"
这是一个S3示例:
# check 1st arg using S3 dispatch and 2nd arg using stopifnot
func3 <- function(a, b) UseMethod("func4")
func3.logical <- function(a, b) {
stopifnot(is.numeric(b))
isTRUE(a) * b
}
func3(TRUE, 3)
## [1] 3
func3(3, 8)
## Error in UseMethod("func3") :
## no applicable method for 'func3' applied to an object of class "c('double', 'numeric')"
CRAN上有一个名为checkmate的软件包,用于进行参数检查,其他许多软件包也使用了该软件包(替换了现已失效的ArgumentCheck软件包)。另一个用于参数类型检查的软件包是Bioconductor上的TypeInfo。
有一个名为rtype的软件包,用于进行强类型检查。
还有用于类型声明的软件包assertive.types,assertive,assertr,assertable和assertthat。
还要注意,关于问题中的代码,S3类是向量,因此可以具有多个元素,因此请使用is.someclass
(如果someclass
中存在这样的函数)或{{ 1}},其中inherits(X, "someclass")
是感兴趣的类,而不是someclass
用于检查S3类。