Menu
CoddyTech

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 do primeiro argumento e chama o método name.class. print() e format() funcionam assim; 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"

Quien realiza la llamada escribe una única llamada, y cada objeto responde à sua própria maneira. Isto é 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() transfere a chamada para o método e nunca retorna: o que quer que o método retorne é o resultado da função genérica, e o código após UseMethod() não é executado. Portanto, uma função genérica tem apenas 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 são divididas em três arquivos. Complete a função genérica area() 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 já 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 ficar em Shape.R, Circle.R e Rectangle.R. main.R contém o código de entrada/saída fornecido 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