强制将特定数据类型强制为函数的参数

时间:2011-08-21 17:15:27

标签: r

我只是想知道是否有办法强制函数只接受某些数据类型,而不必在函数内检查它;或者,这是不可能的,因为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")
  }
}

谢谢,
克里斯

3 个答案:

答案 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"

其他一些信息:

  1. Hadley的devtools wiki是有关所有事情的重要信息来源,包括the S3 object system

  2. S3方法不提供严格的输入。它很容易被滥用。对于更严格的面向对象,请查看原型基于对象的编程的S4 classesreference based classesproto 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 它遇到了一些严重的问题:

  1. 您失去了懒惰的评估,因为您必须评估参数以确定 它的类型。

  2. 在通话时间之前,您仍然无法检查类型;真正的静态类型检查 让你检查一个从未实际发生的呼叫的类型。

  3. 由于R使用延迟评估,(2)可能使类型检查不是很有用, 因为呼叫可能直到很晚才发生,或者永远不会发生。

    (2)的答案是添加静态类型信息。你可能 通过转换表达式来做到这一点,但我认为你不想去那里。