我正在尝试编写一个 S4 类,该类专门返回与输入长度相同的数字向量。 我认为我已经接近成功了;我现在遇到的问题是,我只能从位于我的 GlobalEnv 中的函数中创建新类。
library(S4Vectors)
setClass("TransFunc", contains = c("function"), prototype = function(x) x)
TransFunc <- function(x) {
if (missing(x)) return(new("TransFunc"))
new2("TransFunc", x)
}
.TransFunc.validity <- function(object) {
msg <- NULL
if (length(formals(object)) > 1) {
msg <- c(msg, "TransFunc must only have one argument.")
}
res1 <- object(1:5)
res2 <- object(1:6)
if (length(res1) != 5 || length(res2) != 6) {
msg <- c(msg, "TransFunc output length must equal input length.")
}
if (!class(res1) %in% c("numeric", "integer")) {
msg <- c(msg, "TransFunc output must be numeric for numeric inputs.")
}
if (is.null(msg)) return(TRUE)
msg
}
setValidity2(Class = "TransFunc", method = .TransFunc.validity)
mysqrt <- TransFunc(function(x) sqrt(x))
mysqrt <- TransFunc(sqrt) ## Errors... why??
## Error in initialize(value, ...) :
## 'initialize' method returned an object of class “function” instead
## of the required class “TransFunc”
从function直接继承类的好处是能够像常规函数一样使用它们。
mysqrt(1:5)
## [1] 1.000000 1.414214 1.732051 2.000000 2.236068
body(mysqrt) <- expression(sqrt(x)^2)
mysqrt(1:10)
## [1] 1 2 3 4 5 6 7 8 9 10
为什么在传递函数到全局环境之外时会出现错误?
callNextMethod
进一步概括它,以先使用默认方法,然后测试返回值是否为原始值。这样,我们就不必手动构造一个新的匿名函数。像这样:setMethod("initialize", "TransFunc", function(.Object, ...) {maybe_transfunc <- callNextMethod(); if (is.primitive(maybe_transfunc)) .Object@.Data <- maybe_transfunc else .Object <- maybe_transfunc; .Object})
- ekoamsetClass(...)
和TransFunc
,我运行了TransFunc(sqrt)
甚至是TransFunc(substitute)
并收到了预期的输出。我认为只要initialize
方法没有达到返回步骤,它就不会抛出错误。也许你可以在你的电脑上尝试一下上面的代码?@GradaGukovic - ekoaminitialize
不变,并在构造函数中捕获原始函数,即```TransFunc <- function(x) { if (missing(x)) return(new("TransFunc")); if(is.primitive(x)) x <- function(y) return(x(y)); new2("TransFunc", x); }但我非常忙,现在没有时间测试这个方法。
- Grada Gukovicinitialize()
。这会使代码更难阅读和维护。我通过从traceback()
开始向上工作而不是从类定义向下工作来想出最初的解决方案。 - Grada Gukovic