Нестандартные set-функции в эталонных классах R - PullRequest
0 голосов
/ 15 января 2019

Возможно ли получить синтаксис

foo$bar(x) <- value

для работы, где foo - это объект ссылочного класса, а bar - это метод? То есть возможно ли сделать «назначение подмножества» и иметь «функции замены» в качестве методов в эталонных классах?

Возможен ли синтаксис для других систем OO?

Пример: Я проиллюстрирую это на вымышленном примере использования. Представьте себе справочный класс Person, который содержит некоторую базовую информацию о человеке. В частности, одно поле с именем fullname является именем list:

PersonRCGen <- setRefClass("Person",
                           fields = list(
                             fullname = "list",
                             gender = "character"
                           ))

Далее, мы должны определить некоторые методы для получения и установки определенных имен в списке fullnames, которые (пытаются) дать приведенный выше синтаксис / интерфейс. Моя лучшая попытка до сих пор была:

PersonRCGen$methods(
  name = function(x) { # x is the dataset,
    .self$fullname[[x]]
  },
  `name<-` = function(x, value) {
    .self$fullname[[x]] <- value
  }
)

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

Мы инициализируем новый объект:

a_person <- PersonRCGen$new(fullname = list(first = "Jane", last = "Doe"),
                            gender = "F")

Прямой доступ к полю fullname и доступ к имени и фамилии с помощью определенной функции get работает, как и предполагалось:

a_person$fullname
#$`first`
#[1] "Jane"
# 
#$last
#[1] "Doe"

a_person$name("first")
#[1] "Jane"

a_person$name("last")
#[1] "Doe"

Однако для задания определенного имени в списке fullname мне бы хотелось иметь следующий синтаксис / интерфейс, который, к сожалению, не работает.

a_person$name("first") <- "Jessie"
#Error in a_person$name("first") <- "Jessie" : 
#  target of assignment expands to non-language object

Мне известны следующие работы (которые в основном делают метод плохо названным).

a_person$`name<-`("first", "Johnny")
a_person$fullname
#$`first`
#[1] "Johnny"
#
#$last
#[1] "Doe"

В моем реальном случае использования я бы хотел избежать "традиционных" getName(x) и setName(x, value) имен для функций get и set.

Ответы [ 2 ]

0 голосов
/ 11 февраля 2019

Я не думаю, что вы можете сделать это с желаемым синтаксисом.

Обратите внимание, что вы получите ту же ошибку, если вы выполните какое-либо задание, например,

a_person$hello("first") <- "John"

так что это действительно основная проблема.

Что работает, следующий синтаксис:

name(a_person, "first") <- "John"

В целом вы можете получить что-то вроде ниже:

PersonRCGen <- setRefClass("Person",
                  fields = list(
                    fullname = "list",
                    gender = "character"
                  ),
                  methods = list(
                    initialize = function(...) {
                      initFields(...)
                    },
                    name = function(x) {
                      .self$fullname[[x]]
                    }
                  )
)

setGeneric("name<-", function(x, y, value) standardGeneric("name<-"))
setMethod("name<-", sig = "ANY", function(x, y, value) {
  UseMethod("name<-")
})
# some extras
"name<-.default" <- function(x, y, value) {
  stop(paste("name assignment (name<-) method not defined for class", class(x)))
}
"name<-.list" <- function(x, y, value) {
  x[[y]] <- value
  return(x)
}
# and here specifically
"name<-.Person" <- function(x, y, value) {
  x$fullname[[y]] <- value
  return(x)
}

# example to make use of the above
a_person <- PersonRCGen$new(
  fullname = list(
    first = "Jane",
    last = "Doe"
  ),
  gender = "F"
)

a_person$name("first")
#> [1] "Jane"
name(a_person, "middle") <- "X."
a_person$name("middle")
#> [1] "X."

Я знаю, что это не совсем то, что вы хотите, но я надеюсь, что это поможет.

0 голосов
/ 08 февраля 2019

Я, вероятно, неправильно понимаю, чего вы пытаетесь достичь, но что с этим не так?

person = setRefClass("Person",
                     fields = list(
                       fullname = "list",
                       gender = "character"
                     ))

a_person = person$new(fullname = list(first = "James", last = "Brown"), gender="M")

a_person$fullname$first = "Bob"

a_person

Reference class object of class "Person"
Field "fullname":
$`first`
[1] "Bob"

$last
[1] "Brown"

Field "gender":
[1] "M"
...