как установить значение в объекте S4 r, используя метод (входное значение не требуется) - PullRequest
0 голосов
/ 21 февраля 2019

Это вопрос из двух частей.Я хочу установить значение объекта-прототипа s4 на основе другого значения слотов, и в качестве альтернативы я хочу реализовать это как метод.

У меня есть объект, который я пытаюсь создать.У него есть несколько слотов.Я хотел бы установить значение слотов на основе значений, вставленных из другого слота.Это упрощенная версия того, что я хочу сделать.

, т. Е.

setClass("Person",
    representation(name = "character", age = "numeric", doubleAge = "numeric"),
    prototype(name = "Bob", age = 5, doubleAge = 10) )

Теперь я хочу создать объект, но само значение doubleAge устанавливается на основе слота возраста.

p1 <- new("Person", name = "Alice", age = 6)

Я вижу

An object of class "Person"                                                                                                      
Slot "name":                                                                                                                     
[1] "Alice"                                                                                                                  

Slot "age":                                                                                                                    
[1] 6                                                                                                                        

Slot "doubleAge":                                                                                                              
[1] 10       

, но я хочу, чтобы doubleAge было 12. В прототипе я не знаю, как изменить doubleAge = 10 на что-то вроде doubleAge = 2*age

Поэтому в качестве решения я попытался создать функцию настройки init, которая устанавливает значение после создания.Это вопрос части 2.

setGeneric("init", "Person", function(object) {
    standardGeneric("init")
}
setMethod("init","Person", function(object) {
    object@doubleAge <- object@age*2
    object
}

, если я печатаю object@doubleAge в методе, он возвращает 12, но кажется, что область действия заканчивается, потому что это 10, когда он возвращает

В настоящее время чтоработает очень похоже, но это не правильно.

setGeneric("init<-", "Person", function(object) {
    standardGeneric("init<-")
}
setMethod("init<-","Person", function(object) {
    object@doubleAge <- object@age*2
    object
}

, но тогда я должен назвать как init(p1) <- NULL, что просто кажется странным.Я знаю, что этот пример кажется тривиальным, но это всего лишь простой пример более сложной проблемы реального мира.

Ответы [ 2 ]

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

В дополнение к описанному выше методу для initialize вы можете установить метод для @<-.Причина этого в том, что если вы делаете что-то вроде

x <- new("person", age=5)

, то у вас есть действующий человек с age=5 и doubleage=10.Но что, если вы сейчас сделаете

x@age <- 6

?Теперь age равно 6, но doubleage равно 10, поэтому объект больше не действителен.

В документации R утверждается, что вы можете написать метод для @<-, который исправит это:

setMethod("@<-",signature(object="Person"),function(object,name,value){
  if(name=="age"){
    object@age <- x
    object@doubleAge <- x*2
  } else if(e2=="doubleAge"){
    object@doubleAge <- x
    object@age <- value/2
  } else slot(object,name) <- value
  object
})

, однако, когда вы на самом деле запустите вышеуказанное, вы получите ошибку:

Ошибка в setGeneric (f, где = где): '@ <-' отправляет изнутри;методы могут быть определены, но универсальная функция неявна и не может быть изменена. </p>

Это странно выглядящая ошибка, поскольку мы не пытаемся переопределить универсальный.Фактически, когда мы пытаемся

method.skeleton("@<-",signature(object="Person"))

, мы обнаруживаем, что R неохотно сообщает нам

Ошибка в genericForBasic (name): методы не могут быть определены для примитивной функции '@ <-'в этой версии R </p>

Итак, если вы хотите, чтобы слоты были надежно согласованы, нам придется написать наши собственные методы получения и установки, в соответствии с

setAge <- function(x,value){
  x@age <- value
  x@doubleAge <- value*2
  x
}
0 голосов
/ 21 февраля 2019

Кажется, переопределение метода инициализации сработало для меня.Например,

setClass("Person",
         representation(name = "character", age = "numeric", doubleAge = "numeric"),
         prototype(name = "Bob", age = 5, doubleAge = 10) )

setMethod("initialize", "Person", function(.Object, ...) {
  .Object <- callNextMethod()
  .Object@doubleAge <- .Object@age*2
  .Object
})

(p1 <- new("Person", name = "Alice", age = 6))
# An object of class "Person"
# Slot "name":
# [1] "Alice"
# Slot "age":
# [1] 6
# Slot "doubleAge":
# [1] 12

callNextMethod() запускает инициализатор «по умолчанию», чтобы установить все значения, с которыми мы не связываемся.Затем мы просто изменяем нужные значения и возвращаем обновленный объект.

...