Menu
Coddy logo textTech

Funzioni costruttrici

Fa parte della sezione Programmazione orientata agli oggetti del percorso R di Coddy. Lezione 3 di 57.

Poiché R non controlla mai i campi di un oggetto S3, ogni oggetto di una classe dovrebbe essere creato da una sola funzione, il suo costruttore. Per convenzione, il costruttore di basso livello si chiama new_ seguito dal nome della classe. Accetta ogni campo come argomento, ne controlla i tipi con stopifnot() e restituisce l'oggetto:

new_money <- function(amount = double(), currency = character()) {
  stopifnot(is.double(amount), is.character(currency))
  structure(list(amount = amount, currency = currency), class = "money")
}
m <- new_money(9.5, "EUR")
cat(m$amount, m$currency)

Output:

9.5 EUR

stopifnot() interrompe il programma quando una delle sue condizioni non è TRUE, e il messaggio indica il controllo non superato. Un tipo errato viene rilevato nel momento in cui l’oggetto viene creato, non in seguito, quando viene usato da un’altra funzione:

new_money <- function(amount = double(), currency = character()) {
  stopifnot(is.double(amount), is.character(currency))
  structure(list(amount = amount, currency = currency), class = "money")
}
m <- new_money("9.5", "EUR")

Output:

Error in new_money("9.5", "EUR") : is.double(amount) is not TRUE
Calls: new_money -> stopifnot
Execution halted

Il costruttore è l’unico punto in cui viene chiamata structure() per la classe, quindi ogni oggetto ha gli stessi campi nello stesso ordine. Il codice che ha bisogno di molti oggetti la chiama in un ciclo o con lapply():

new_point <- function(x = 0, y = 0) {
  stopifnot(is.numeric(x), is.numeric(y))
  structure(list(x = x, y = y), class = "point")
}
pts <- lapply(1:3, function(i) new_point(i, i * i))
for (p in pts) cat(p$x, p$y, "\n")

Output:

1 1 
2 4 
3 9 

Un oggetto S3 non deve necessariamente essere una lista. Un costruttore può assegnare un'etichetta a un vettore semplice e memorizzare informazioni aggiuntive come attributi, come avviene per i fattori e le date di R. attr(x, "unit") legge un attributo:

new_distance <- function(value = double(), unit = "m") {
  stopifnot(is.double(value), is.character(unit))
  structure(value, unit = unit, class = "distance")
}
d <- new_distance(c(1.5, 2), "km")
print(attr(d, "unit"))
print(unclass(d)[2] * 1000)

Output:

[1] "km"
[1] 2000
challenge icon

Sfida

Facile

Completa il costruttore new_book(title, author, pages) in Book.R. Verifica con stopifnot() che title e author siano caratteri e che pages sia numerico, quindi restituisce una lista con questi tre campi e la classe book. Poi completa book_label(b), che restituisce Dune by Frank Herbert, 412 pages.

Il codice fornito legge righe title;author;pages. Passa pages come numero quando è composto da cifre e come testo originale altrimenti, stampa book: e l'etichetta per ogni oggetto, e stampa rejected: e il titolo quando il costruttore si interrompe.

Il tuo codice va in Book.R. main.R contiene il codice di input/output fornito e non può essere modificato.

Provalo tu

source("Book.R")

# Supplied input/output code: keep it as it is
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  p <- strsplit(line, ";")[[1]]
  pages <- if (grepl("^[0-9]+$", p[3])) as.numeric(p[3]) else p[3]
  b <- tryCatch(new_book(p[1], p[2], pages), error = function(e) NULL)
  if (is.null(b)) {
    cat("rejected: ", p[1], "\n", sep = "")
  } else {
    cat(class(b), ": ", book_label(b), "\n", sep = "")
  }
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore R online