Genéricos y UseMethod
Parte de la sección Programación orientada a objetos del Journey de R de Coddy. Lección 7 de 57.
Un genérico es una función cuyo cuerpo es UseMethod("name"). Cuando se llama, examina la clase de su primer argumento y llama al método name.class. print() y format() funcionan así; tú también puedes escribir tus propios genéricos:
speak <- function(x) UseMethod("speak")
speak.dog <- function(x) paste(x$name, "says woof")
speak.cat <- function(x) paste(x$name, "says meow")
rex <- structure(list(name = "Rex"), class = "dog")
tom <- structure(list(name = "Tom"), class = "cat")
print(speak(rex))
print(speak(tom))Salida:
[1] "Rex says woof"
[1] "Tom says meow"La persona que llama escribe una llamada, y cada objeto responde a su manera. Esto es polimorfismo: el código que recorre una lista mixta no necesita un if para cada clase:
speak <- function(x) UseMethod("speak")
speak.dog <- function(x) paste(x$name, "says woof")
speak.cat <- function(x) paste(x$name, "says meow")
pets <- list(structure(list(name = "Rex"), class = "dog"),
structure(list(name = "Tom"), class = "cat"),
structure(list(name = "Bo"), class = "dog"))
for (p in pets) cat(speak(p), "\n")Salida:
Rex says woof
Tom says meow
Bo says woof Un método toma los argumentos del genérico. Dale al genérico un parámetro ... para que los métodos puedan aceptar argumentos adicionales propios, como digits para un círculo:
area <- function(shape, ...) UseMethod("area")
area.square <- function(shape, ...) shape$side^2
area.circle <- function(shape, digits = 2, ...) round(pi * shape$r^2, digits)
sq <- structure(list(side = 3), class = "square")
ci <- structure(list(r = 1), class = "circle")
print(area(sq))
print(area(ci))
print(area(ci, digits = 4))Salida:
[1] 9
[1] 3.14
[1] 3.1416UseMethod() pasa la llamada al método y nunca regresa: lo que devuelva el método es el resultado del genérico, y el código posterior a UseMethod() no se ejecuta. Por lo tanto, un genérico consta de una sola línea:
size <- function(x) {
UseMethod("size")
cat("this line never runs\n")
}
size.box <- function(x) x$w * x$h
b <- structure(list(w = 2, h = 5), class = "box")
print(size(b))Salida:
[1] 10Desafío
FácilLas formas se dividen en tres archivos. Completa la función genérica area() en Shape.R y, después, añade los métodos area.circle() (pi por el radio al cuadrado) en Circle.R y area.rectangle() (ancho por alto) en Rectangle.R. Los constructores están dados.
El código proporcionado lee líneas circle 2 o rectangle 3 4 e imprime la clase y el área de cada forma con dos decimales: circle: 12.57.
Tu código va en Shape.R, Circle.R y Rectangle.R. main.R contiene el código proporcionado de entrada/salida y no se puede editar.
Pruébalo tú mismo
source("Shape.R")
source("Circle.R")
source("Rectangle.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]]
s <- if (p[1] == "circle") new_circle(as.numeric(p[2])) else new_rectangle(as.numeric(p[2]), as.numeric(p[3]))
cat(sprintf("%s: %.2f", class(s), area(s)), "\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