2015-05-31 4 views
5

Я создаю пакет R с классами S4, и у меня возникают проблемы с функцией new. У меня есть класс с именем ConfigsS4 классы: аргументы, переданные new(), не входят в их слоты

setClass("Configs", 
    slots = list(
    burnin = "numeric", 
    chains = "numeric", 
    features = "numeric", 
    iterations = "numeric", 
    mphtol = "numeric", 
    samples = "numeric", 
    seed = "numeric", 
    thin = "numeric", 
    verbose = "numeric" 
), 
    prototype = list(
    burnin = 0, 
    chains = 2, 
    features = 5, 
    iterations = 5, 
    mphtol = 1e-4, 
    samples = 3, 
    seed = sample(1e6, 1), 
    thin = 0, 
    verbose = 0 
) 
) 

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

> new("Configs", features = 1000) 
An object of class "Configs" 
Slot "burnin": 
[1] 0 

Slot "chains": 
[1] 2 

Slot "features": 
[1] 1000 

Slot "iterations": 
[1] 5 

Slot "mphtol": 
[1] 1e-04 

Slot "samples": 
[1] 3 

Slot "seed": 
[1] 437211 

Slot "thin": 
[1] 0 

Slot "verbose": 
[1] 0 

Однако, когда я устанавливаю весь пакет, загрузите его в свежую среду, и запустить new("Configs", features = 1000), я получаю features из 5. Почему не new() значения положить в слоты больше?

Мой пакет прошел R CMD check без каких-либо ошибок, предупреждений или заметок. Вот моя информация о сеансе.

> sessionInfo() 
R version 3.2.0 (2015-04-16) 
Platform: x86_64-unknown-linux-gnu (64-bit) 
Running under: CentOS release 6.6 (Final) 

locale: 
[1] LC_CTYPE=en_US.UTF-8  LC_NUMERIC=C    
[3] LC_TIME=en_US.UTF-8  LC_COLLATE=en_US.UTF-8  
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 
[7] LC_PAPER=en_US.UTF-8  LC_NAME=C     
[9] LC_ADDRESS=C    LC_TELEPHONE=C    
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C  

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

other attached packages: 
[1] heterosis_0.0 pracma_1.8.3 MCMCpack_1.3-3 MASS_7.3-40 coda_0.17-1 

loaded via a namespace (and not attached): 
[1] tools_3.2.0  grid_3.2.0  lattice_0.20-31 

Edit: Я получил его, но я до сих пор не удовлетворены.

Оказалось, что моя функция initialize вызывает проблемы.

setMethod("initialize", "Configs", function(.Object, ...){ 
# .Object = new("Configs", ...) 
    validObject(.Object)  
    return(.Object) 
}) 

Когда я его удаляю, new снова помещает вещи в слоты. Я рад, что нашел проблему, но я не хочу полностью отключать функцию инициализации. Я хочу удобный способ вызвать validObject и выполнить другую проверку ошибок, и initialize кажется подходящим и подходящим местом для этого. И если я раскомментирую прокомментированную строку, я получаю бесконечную рекурсию. Как создать конструктор без нарушения new?

ответ

6

initialize() - двухпозиционный - инициализация и копирование. Это, как правило, лучше (и более информативным для пользователя), чтобы обеспечить явный конструктор

.A = setClass("A", representation(x="numeric")) 

A = function(x=numeric(), ...) 
    .A(x=x, ...) 

validOjbect() вызывается по умолчанию ИНИЦИАЛИЗИРУЙТЕ метод при создании объекта включает в себя назначение слотов, поэтому нет необходимости вызывать его в явном виде во время вашего собственного Initialize метод (см. ниже); может быть, вы бы

.A = setClass("A", representation(x="numeric"), 
    prototype=prototype(x=NA_integer_)) 

setValidity("A", function(object) { 
    if (length([email protected]) != 1L) 
     "'x' must be length 1" 
    else TRUE 
}) 

A = function(x=NA_integer_, ...) 
    ## signature is informative -- 'x' is integer(1), not just '...' 
    ## coercion (e.g., as.integer(), below) and other set-up 
    new("A", x=as.integer(x), ...) 

с

> A() 
An object of class "A" 
Slot "x": 
[1] NA 

> A(x=1) 
An object of class "A" 
Slot "x": 
[1] 1 

> A(x=1:2) 
Error in validObject(.Object) : 
    invalid class "A" object: 'x' must be length 1 

Важное предостережение о том, что метод Ценностьь не вызывается, когда нет слотов инициализированы пользователем, поэтому prototype() должен быть определен для создания действительного объекта (проверьте это с помощью validObject(new("A")).

Для вашего вопроса функция достоверности - это правильное место для «проверки других ошибок». Очень сложно написать правильный init Метод ialize, но что-то ближе, чтобы исправить это

.B = setClass("B", 
    representation(x="numeric", y="numeric"), 
    prototype=prototype(x=NA_integer_, y=NA_real_)) 
setMethod("initialize", "B", 
    function(.Object, ..., [email protected], [email protected]) 
{ 
    ## pre-processing, then invoke 'next' initialize() method 
    ## base initialize() creates the object then calls validObject() 
    ## so no need for explicit test of validity 
    .Object <- callNextMethod(.Object, ..., x=x, y=y) 
    ## post-processing 
    .Object 
}) 

Такого рода странные конструкции позволяет initialize() продолжать вести себя как конструктор копирования

> b = new("B", x=1, y=2) # constructor 
> initialize(b, x=2)  # copy-constructor 
An object of class "B" 
Slot "x": 
[1] 2 

Slot "y": 
[1] 2 

что очень важно во время наследования классов.Но, как вы видите, это довольно сложно - в конце концов, это очень сложно и редко стоит того, чтобы правильно исправить initialize().

Обратите внимание, что мы не полностью выполнили договор initialize(),

setClass("C", representation(x="numeric", y="numeric")) # default initialize() 

, который фактически действует как конструктор копирования при вызове с new()

> c = new("C", x=1, y=2) 
> new("C", c, x=2) 
An object of class "C" 
Slot "x": 
[1] 2 

Slot "y": 
[1] 2 

по сравнению с отсутствием конструкции копирования для реализации Б

> b = new("B", x=1, y=2) 
> new("B", b, x=2) 
An object of class "B" 
Slot "x": 
[1] 2 

Slot "y": 
[1] NA 
+0

Спасибо, это помогает. Я действительно хотел узнать больше о конструкторах в R, не осознавая этого. – landau