Автоматизация присвоения в методах initialize() для эталонных классов в R

#r #reference-class

#r #ссылочный класс

Вопрос:

Я работаю со ссылочным классом с несколькими десятками полей. Я настроил initialize() метод, который принимает объект list. В то время как некоторые поля зависят от дальнейших вычислений из элементов списка, большинство полей назначаются непосредственно из элементов списка как таковых:

 fieldA <<- list$A
fieldB <<- list$B
  

Я подумал, что было бы неплохо немного автоматизировать это. Приведу пример в псевдокоде R (этот пример, очевидно, не сработает):

 for (field in c('A', 'B', 'C', 'D'))
   field <<- list[[field]]
  

Я попытался выполнить несколько конечных запусков вокруг <<- , например, делая что-то вроде:

 for field in c('A', 'B', 'C', 'D'))
  do.call('<<-' c(field, list[[field]])) 
  

но нет кости.

Я предполагаю, что такого рода поведение просто невозможно в текущем воплощении ссылочных классов, но подумал, что, возможно, стоит посмотреть, знает ли кто-нибудь в SO land о лучшем способе сделать это.

Ответ №1:

Используйте .self для указания экземпляра и выбора полей с помощью [[ . Я не уверен на 100% (но кто вообще уверен?) это [[ строго законно. Я добавил значения по умолчанию в lst , поэтому оно работает при вызове как C$new() , неявное предположение в S4, которое, похоже, сработает аналогичным образом с ссылочными классами.

 C <- setRefClass("C",
    fields=list(a="numeric", b="numeric", c="character"),
    methods=list(
      initialize=function(..., lst=list(a=numeric(), b=numeric(), c=character()) 
        {
          directflds <- c("a", "b")
          for (elt in directflds)
              .self[[elt]] <- lst[[elt]]
          .self$c <- as.character(lst[["c"]])
          .self
      }))
c <- C$new(lst=list(a=1, b=2, c=3))
  

Или оставьте возможность передавать список или сами элементы пользователю с

 B <- setRefClass("B",
    fields=list(a="numeric", b="numeric", c="character"),
    methods=list(
      initialize=function(..., c=character()) {
          callSuper(...)
          .self$c <- as.character(c)
          .self
      }))
b0 <- B$new(a=1, b=2, c=3)
b1 <- do.call(B$new, list(a=1, b=2, c=3))
  

Это также кажется более терпимым к пропуску некоторых значений при вызове new() .