我只是想知道是否有办法强制函数只接受某些数据类型,而不必在函数内检查它;或者,这是不可能的,因为R的类型检查是在运行时完成的(而不是那些编程语言,例如Java,在编译期间进行类型检查)?
例如,在Java中,您必须指定数据类型:
class t2 {
public int addone (int n) {
return n+1;
}
}
在R中,类似的功能可能是
addone <- function(n)
{
return(n+1)
}
但如果提供了一个向量,则(显然)将返回一个向量。如果你只想接受一个整数,那么就是在函数中有一个条件的唯一方法,就像
一样。addone <- function(n)
{
if(is.vector(n) && length(n)==1)
{
return(n+1)
} else
{
return ("You must enter a single integer")
}
}
谢谢,
克里斯
答案 0 :(得分:18)
这完全可以使用S3类。你的例子在上下文或R中有点做作,因为我想不出为什么人们想要创建单个值的类的实际原因。尽管如此,这是可能的。作为一个额外的好处,我演示了如何使用函数addone将一个值添加到数字向量(平凡)和字符向量(所以A转到B等):
首先为addone
创建一个通用的S3方法,启用S3发送机制UseMethod
:
addone <- function(x){
UseMethod("addone", x)
}
接下来,创建设想的类single
,定义为传递给它的任何内容的第一个元素:
as.single <- function(x){
ret <- unlist(x)[1]
class(ret) <- "single"
ret
}
现在创建处理各种类的方法。除非定义了特定的类,否则将调用默认方法:
addone.default <- function(x) x + 1
addone.character <- function(x)rawToChar(as.raw(as.numeric(charToRaw(x))+1))
addone.single <- function(x)x + 1
最后,使用一些示例数据对其进行测试:
addone(1:5)
[1] 2 3 4 5 6
addone(as.single(1:5))
[1] 2
attr(,"class")
[1] "single"
addone("abc")
[1] "bcd"
其他一些信息:
Hadley的devtools wiki是有关所有事情的重要信息来源,包括the S3 object system。
S3方法不提供严格的输入。它很容易被滥用。对于更严格的面向对象,请查看原型基于对象的编程的S4 classes,reference based classes或proto package。
答案 1 :(得分:5)
我发现stopifnot()对这些情况非常有用。
x <- function(n) {
stopifnot(is.vector(n) && length(n)==1)
print(n)
}
它之所以如此有用,是因为如果条件为false,它会向用户提供非常清晰的错误消息。
答案 2 :(得分:4)
您可以编写如下所示的包装器:
check.types = function(classes, func) {
n = as.name
params = formals(func)
param.names = lapply(names(params), n)
handler = function() { }
formals(handler) = params
checks = lapply(seq_along(param.names), function(I) {
as.call(list(n('assert.class'), param.names[[I]], classes[[I]]))
})
body(handler) = as.call(c(
list(n('{')),
checks,
list(as.call(list(n('<-'), n('.func'), func))),
list(as.call(c(list(n('.func')), lapply(param.names, as.name))))
))
handler
}
assert.class = function(x, cls) {
stopifnot(cls %in% class(x))
}
并像
一样使用它f = check.types(c('numeric', 'numeric'), function(x, y) {
x + y
})
> f(1, 2)
[1] 3
> f("1", "2")
Error: cls %in% class(x) is not TRUE
R没有装饰器使得有点不方便。这有点hacky 它遇到了一些严重的问题:
您失去了懒惰的评估,因为您必须评估参数以确定 它的类型。
在通话时间之前,您仍然无法检查类型;真正的静态类型检查 让你检查一个从未实际发生的呼叫的类型。
由于R使用延迟评估,(2)可能使类型检查不是很有用, 因为呼叫可能直到很晚才发生,或者永远不会发生。
(2)的答案是添加静态类型信息。你可能 通过转换表达式来做到这一点,但我认为你不想去那里。