Определить оператор скобки (`[`) в классе R6

Вот что не работает:

library(R6)

Foo = R6::R6Class(
    'Foo',
    public = list(
        X = NULL,
        metadata = NULL,
        initialize = function(X, metadata){
            self$X = X
            self$metadata = metadata
        },
        `[` = function(selection){
            subfoo = Foo$new(X = X[selection], 
                             metadata = self$metadata)
            return(subfoo)
        }
    )
)

В частности, [ Метод мусора:

> X = matrix(1:8, ncol = 2)
> foo = Foo$new(X, 'blah blah')
> foo[1:2,]
Error in foo[1:2, ] : object of type 'environment' is not subsettable

Желаемый результат заключается в том, что foo[1:2,] будет объектом класса Foo как foo кроме того, что его матрица foo$X меньше Есть ли прямой способ реализации этого, который подвергает [ оператор напрямую к пользователю?

1 ответ

Ответ лучше поздно, чем никогда, я полагаю. Проблема в том, что вы регистрируете методы, которые могут быть вызваны как

x$`[`(1:3)

тогда как ты хочешь

x[1:3]

Следующее будет отправлять все [ а также [<- звонки (через S3) правильно для всех объектов R6.

`[.R6` <- function(x, ...) x$`[`(...) 
`[<-.R6` <- function(x, ...) x$`[<-`(...) 

Обратите внимание, что вы не должны делать ничего подобного для [[ методы, так как они уже определены и используются, потому что объекты R6 являются средами.

В идеале было бы здорово, если ( также может быть переопределено, чтобы мы могли создавать объекты функтора (например, вызов x(2)), но я не знаю, как это можно сделать..

Если другие тоже его ищут, вот полный рабочий пример того, как это сделать (на основе ответа Яна Феллоуз):

library(R6)

Foo = R6::R6Class(
  'Foo',
  public = list(
    x = NULL,
    initialize = function(x) {
      self$x = x
    },
    
    `[` = function(idx) {
      self$x[idx]
    },
    
    `[<-` = function(idx, value) {
      self$x[idx] <- value
      invisible(self)  # important!
    },
    
    length = function() {
      length(self$x)
    }
  )
)

# set up method dispatch
`[.Foo`    <- function(obj, ...) obj$`[`(...) 
`[<-.Foo`  <- function(obj, ...) obj$`[<-`(...) 
length.Foo <- function(obj, ...) obj$length(...)

# test
foo <- Foo$new(c(1,2,3))
(n <- length(foo))
#> [1] 3
foo[1:n]
#> [1] 1 2 3
foo[2] <- 0
foo[1:n]
#> [1] 1 0 3

Создано 2020-10-09 пакетом REPEX (v0.3.0)

(Возвращаемое значение может быть другим объектом Foo, если вам это нужно. Я возвращаю вектор для простоты)

Другие вопросы по тегам