Menu
Coddy logo textTech

Generics und UseMethod

Teil des Abschnitts Objektorientierte Programmierung der R-Journey von Coddy. Lektion 7 von 57.

Ein Generikum ist eine Funktion, deren Rumpf UseMethod("name") enthält. Wenn sie aufgerufen wird, betrachtet sie die Klasse ihres ersten Arguments und ruft die Methode name.class auf. print() und format() funktionieren auf diese Weise; du kannst auch eigene Generika schreiben:

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))

Ausgabe:

[1] "Rex says woof"
[1] "Tom says meow"

Der Aufrufer schreibt einen Aufruf, und jedes Objekt antwortet auf seine eigene Weise. Das ist Polymorphismus: Code, der eine gemischte Liste durchläuft, benötigt kein if für jede Klasse:

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")

Ausgabe:

Rex says woof 
Tom says meow 
Bo says woof 

Eine Methode übernimmt die Argumente des Generics. Gib dem Generic einen ...-Parameter, damit Methoden zusätzliche eigene Argumente akzeptieren können, etwa digits für einen Kreis:

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))

Ausgabe:

[1] 9
[1] 3.14
[1] 3.1416

UseMethod() übergibt den Aufruf an die Methode und kehrt nie zurück: Was auch immer die Methode zurückgibt, ist das Ergebnis des Generics, und Code nach UseMethod() wird nicht ausgeführt. Ein Generic besteht daher aus einer Zeile:

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))

Ausgabe:

[1] 10
challenge icon

Aufgabe

Einfach

Die Shapes sind auf drei Dateien verteilt. Vervollständige die generische area() in Shape.R und füge anschließend die Methoden area.circle() (pi mal dem Quadrat des Radius) in Circle.R und area.rectangle() (Breite mal Höhe) in Rectangle.R hinzu. Die Konstruktoren sind vorgegeben.

Der bereitgestellte Code liest Zeilen wie circle 2 oder rectangle 3 4 ein und gibt die Klasse und die Fläche jeder Shape mit zwei Dezimalstellen aus: circle: 12.57.

Dein Code gehört in Shape.R, Circle.R und Rectangle.R. main.R enthält den bereitgestellten Ein-/Ausgabecode und darf nicht bearbeitet werden.

Probier es selbst

source("Shape.R")
source("Circle.R")
source("Rectangle.R")

# Gelieferter Ein-/Ausgabe-Code: belasse ihn wie er ist
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 dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-R-Compiler