Menu
CoddyTech

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") ist. Wenn sie aufgerufen wird, prüft 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, braucht nicht für jede Klasse ein if:

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 der generischen Funktion. Gib der generischen Funktion einen ...-Parameter, damit Methoden eigene zusätzliche Argumente annehmen können, zum Beispiel 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 der generischen Funktion, und Code nach UseMethod() wird nicht ausgeführt. Eine generische Funktion 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 Formen sind auf drei Dateien verteilt. Vervollständige die generische Funktion area() in Shape.R und füge dann die Methoden area.circle() (Pi mal Radius zum Quadrat) 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 für jede Form ihre Klasse und ihre Fläche 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")

# Vorgegebener Eingabe-/Ausgabecode: unverändert lassen
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