Menu
Coddy logo textTech

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.1416

UseMethod() 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] 10
challenge icon

Desafio

Fácil

As 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 = "")
}
quiz iconTeste seus conhecimentos

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

Pratique por conta própria: Compilador de R online