为什么矩阵“保护”自身以及如何对自定义类实施真正的限制?

时间:2013-10-03 10:13:18

标签: r oop

我一直在努力让对手的有效性得到提升。我读过Hadley's advanced programming并得到他所说的瞄准你的脚(用枪):

  R不会保护你自己:你可以很容易地用脚射击自己,但是如果你没有用枪瞄准你的脚并扣动扳机,你就不会有问题。

所以这适用于S3。为了寻求更严格的实施,我调查了S4setValidity的手册页提出了以下内容:

setClass("track",
      representation(x="numeric", y = "numeric"))
t1 <- new("track", x=1:10, y=sort(stats::rnorm(10)))
## A valid "track" object has the same number of x, y values
validTrackObject <- function(object) {
if(length(object@x) == length(object@y)) TRUE
else paste("Unequal x,y lengths: ", length(object@x), ", ",
           length(object@y), sep="")
}
## assign the function as the validity method for the class
setValidity("track", validTrackObject)
## t1 should be a valid "track" object
validObject(t1)
## Now we do something bad
t2 <- t1
t2@x <- 1:20
## This should generate an error
## Not run: try(validObject(t2))

底线:如果我没有将validObject添加到初始化器或构造函数中,那么我无能为力。同样来自Martin Morgan and bioconductor's Seth Falcon的这篇文章很有意思,尽管我总是t2@x <- 1:1111

我想我能做些什么呢?虽然例如matrix类让我想知道是否有选项。

a <- matrix(c(1:12),3,4)
cbind(a,"somechar")
# or similarily
a[1,1] <- "b"

显然,matrix的所有元素必须属于同一类。这就是为什么一旦添加了一个字符,所有元素都被强制转换为公共分母,即character类。

所以我的问题是:这怎么可能?以什么方式定义矩阵类,它可以通过任何方式保护“所有元素的某些类”的限制?有没有办法对自定义类实现这样的限制?

例如:类'customlist'的类必须是命名列表,并且名称仅限于两个字符长。

1 个答案:

答案 0 :(得分:1)

AFAIK,没有办法阻止你(或你的用户)做任务愚蠢的事情,而不是可能覆盖<-。由于这是原始的,而且对于R来说非常基础,如果沿着这条路走下去,就有可能打破其他事情。

如果使用引用类,则可以包含允许在进行分配之前进行检查的访问器。

trackFactory <- setRefClass(
  "track",
  fields = list(
    x = "numeric",
    y = "numeric"
  ),
  methods = list(
    initialize = function(x, y)
    {
      assertIsValid(x, y)
      x <<- x
      y <<- y
    },
    assertIsValid = function(x, y)
    {
      if(length(x) != length(y)) 
      {
        stop(
          "Unequal x,y lengths: ", 
          toString(c(length(x), length(y)))
        )
      }
    },
    setX = function(x)
    {
      assertIsValid(x, .self$y)
      x <<- x
    },
    setY = function(y)
    {
      assertIsValid(.self$x, y)
      y <<- y
    }
  )
)

track1 <- trackFactory$new(1:10, runif(10))
track1$setX(1:5)
## Error in assertIsValid(x, .self$y) : Unequal x,y lengths: 5, 10

不幸的是,您仍然可以使用直接分配来跳过检查。

track1$x <- 1:7