Genéricos e UseMethod
Parte da seção Programação Orientada a Objetos do Journey de R da Coddy. Lição 7 de 57.
Um genérico é uma função cujo corpo é UseMethod("name"). Quando é chamada, ela verifica a classe de seu primeiro argumento e chama o método name.class. print() e format() funcionam dessa forma; você também pode escrever seus próprios 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))Saída:
[1] "Rex says woof"
[1] "Tom says meow"Quem chama faz uma chamada, e cada objeto responde à sua própria maneira. Isso é polimorfismo: o código que percorre uma lista mista não precisa de um if para cada classe:
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")Saída:
Rex says woof
Tom says meow
Bo says woof Um método recebe os argumentos do genérico. Dê ao genérico um parâmetro ... para que os métodos possam aceitar argumentos extras próprios, como digits para um 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))Saída:
[1] 9
[1] 3.14
[1] 3.1416UseMethod() passa a chamada para o método e nunca retorna: o que quer que o método retorne é o resultado do genérico, e o código após UseMethod() não é executado. Portanto, um genérico é uma linha:
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))Saída:
[1] 10Desafio
FácilAs formas estão divididas em três arquivos. Complete a area() genérica em Shape.R e, em seguida, adicione os métodos area.circle() (pi vezes o raio ao quadrado) em Circle.R e area.rectangle() (largura vezes altura) em Rectangle.R. Os construtores são fornecidos.
O código fornecido lê linhas circle 2 ou rectangle 3 4 e imprime a classe e a área de cada forma com duas casas decimais: circle: 12.57.
Seu código deve estar em Shape.R, Circle.R e Rectangle.R. main.R contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
source("Shape.R")
source("Circle.R")
source("Rectangle.R")
# Código de entrada/saída fornecido: mantenha-o 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 lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos do S3
Trabalhando com ArquivosListas com uma ClasseFunções ConstrutorasMétodos de Impressão e FormataçãoValidadores e AuxiliaresRevisão - Temperaturas4Encapsulamento em R
Closures como ObjetosAmbientes como ObjetosFunções de AcessoProtegendo o EstadoRecapitulação - Parquímetro2Genéricos e Métodos S3
Genéricos e UseMethodMétodos padrãoMétodos para genéricos baseFundamentos de NextMethodRevisão - Áreas de formas5Classes S4
Definindo classes S4Slots e acessoVerificações de validadeMétodos showRevisão - Catálogo de produtos8Classes de Referência
Definindo Classes de ReferênciaMétodos e Atualizações de CamposSemântica de CópiaHerança e callSuperRecapitulação — Fila de Tarefas11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de LivrosPratique por conta própria: Compilador de R online