Funciones constructoras
Parte de la sección Programación orientada a objetos del Journey de R de Coddy. Lección 3 de 57.
Como R nunca comprueba los campos de un objeto S3, cada objeto de una clase debe construirse mediante una función, su constructor. Por convención, el constructor de bajo nivel se llama new_ seguido del nombre de la clase. Toma cada campo como argumento, comprueba los tipos con stopifnot() y devuelve el objeto:
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)Salida:
9.5 EURstopifnot() detiene el programa cuando una de sus condiciones no es TRUE, y el mensaje indica cuál comprobación ha fallado. Un tipo incorrecto se detecta en el momento en que se construye el objeto, no más tarde, cuando alguna otra función lo utiliza:
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")Salida:
Error in new_money("9.5", "EUR") : is.double(amount) is not TRUE
Calls: new_money -> stopifnot
Execution haltedEl constructor es el único lugar que llama a structure() para la clase, por lo que cada objeto tiene los mismos campos en el mismo orden. El código que necesita muchos objetos lo llama en un bucle 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")Salida:
1 1
2 4
3 9 Un objeto S3 no tiene que ser una lista. Un constructor puede etiquetar un vector simple y almacenar información adicional como atributos, que es la forma en que funcionan los factores y las fechas propios de R. attr(x, "unit") lee un atributo:
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)Salida:
[1] "km"
[1] 2000Desafío
FácilCompleta el constructor new_book(title, author, pages) en Book.R. Comprueba con stopifnot() que title y author sean de tipo carácter y que pages sea numérico, y devuelve una lista con esos tres campos y la clase book. Después completa book_label(b), que devuelve Dune by Frank Herbert, 412 pages.
El código proporcionado lee líneas con el formato title;author;pages. Pasa pages como un número cuando está compuesto por dígitos y como el texto original en caso contrario, imprime book: y la etiqueta de cada objeto, e imprime rejected: y el título cuando el constructor se detiene.
Tu código va en Book.R. main.R contiene el código proporcionado de entrada/salida y no se puede editar.
Pruébalo tú mismo
source("Book.R")
# Código de entrada/salida suministrado: déjalo tal como está
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 = "")
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Fundamentos de S3
Trabajar con archivosListas con una claseFunciones constructorasMétodos de impresión y formatoValidadores y auxiliaresRepaso: temperaturas4Encapsulación en R
Cierres como objetosEntornos como objetosFunciones de accesoProtección del estadoRepaso: parquímetro2S3 Genéricos y métodos
Genéricos y UseMethodMétodos predeterminadosMétodos para genéricos baseFundamentos de NextMethodRepaso: áreas de figuras5Clases S4
Definición de clases S4Slots y accesoComprobaciones de validezMétodos showRepaso - Catálogo de productos8Clases de referencia
Definición de clases de referenciaMétodos y actualizaciones de camposSemántica de copiaHerencia y callSuperRepaso: cola de tareas11Proyecto: Gestión de biblioteca
Libros y miembrosPréstamo de librosPractica por tu cuenta: Compilador de R online