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

Chr*_*isW 10 r

我只是想知道是否有办法强制函数只接受某些数据类型,而不必在函数内检查它; 或者,这是不可能的,因为R的类型检查是在运行时完成的(而不是那些编程语言,例如Java,在编译期间进行类型检查)?

例如,在Java中,您必须指定数据类型:

class t2 {
    public int addone (int n) {
        return n+1;
    }
}
Run Code Online (Sandbox Code Playgroud)

在R中,可能有类似的功能

addone <- function(n)
{
    return(n+1)
}
Run Code Online (Sandbox Code Playgroud)

但是如果提供了一个向量,则(显然)将返回一个向量.如果你只想接受一个整数,那么这是在函数中有一个条件的唯一方法,就像

addone <- function(n)
{
  if(is.vector(n) && length(n)==1)
  {
    return(n+1)
  } else
  {
    return ("You must enter a single integer")
  }
}
Run Code Online (Sandbox Code Playgroud)

谢谢,
克里斯

And*_*rie 18

这完全可以使用S3类.你的例子在上下文或R中有点做作,因为我想不出为什么人们想要创建单个值的类的实际原因.尽管如此,这是可能的.作为一个额外的好处,我演示了如何使用函数addone将一个值添加到数字向量(平凡)和字符向量(所以A转到B等):

首先创建一个通用的S3方法addone,使用S3调度机制UseMethod:

addone <- function(x){
  UseMethod("addone", x)
}
Run Code Online (Sandbox Code Playgroud)

接下来,创建一个人为的类single,定义为传递给它的任何东西的第一个元素:

as.single <- function(x){
  ret <- unlist(x)[1]
  class(ret) <- "single"
  ret
}
Run Code Online (Sandbox Code Playgroud)

现在创建处理各种类的方法.除非定义了特定的类,否则将调用默认方法:

addone.default <- function(x) x + 1
addone.character <- function(x)rawToChar(as.raw(as.numeric(charToRaw(x))+1))
addone.single <- function(x)x + 1
Run Code Online (Sandbox Code Playgroud)

最后,使用一些示例数据对其进行测试:

addone(1:5)
[1] 2 3 4 5 6

addone(as.single(1:5))
[1] 2
attr(,"class")
[1] "single"

addone("abc")
[1] "bcd"
Run Code Online (Sandbox Code Playgroud)

一些其他信息:

  1. Hadley的devtools wiki是所有事物的宝贵信息来源,包括S3对象系统.

  2. S3方法不提供严格的输入.它很容易被滥用.对于更严格的面向对象,请查看S4类,基于引用的类或Prototype基于对象的编程的proto包.


Owe*_*wen 5

您可以编写如下的包装器:

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))
}
Run Code Online (Sandbox Code Playgroud)

并使用它

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
Run Code Online (Sandbox Code Playgroud)

由于 R 没有装饰器,这有点不方便。这有点像hacky,并且存在一些严重的问题:

  1. 你失去了惰性求值,因为你必须求值一个参数来确定它的类型。

  2. 在通话时间之前,您仍然无法检查类型;真正的静态类型检查允许您检查甚至从未实际发生的调用的类型。

由于 R 使用惰性求值,(2) 可能使类型检查不是很有用,因为调用可能实际上直到很晚才发生,或者永远不会发生。

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


Bra*_*sen 5

我发现stopifnot()对这些情况也非常有用.

x <- function(n) { 
stopifnot(is.vector(n) && length(n)==1)
print(n)
}
Run Code Online (Sandbox Code Playgroud)

它如此有用的原因是因为如果条件为假,它会向用户提供非常明确的错误消息.

  • 请注意,这可以写成`stopifnot(is.vector(n),length(n)== 1)`并且这将具有以下优点:如果失败,那么失败的两个条件中的哪一个将作为错误信息. (3认同)