Menu
CoddyTech

Tworzenie funkcji generycznych

Część sekcji Programowanie obiektowe ścieżki R w Coddy. Lekcja 27 z 57.

Funkcję generyczną S4 tworzy się za pomocą setGeneric(). Jej ciało funkcji to standardGeneric("name"), odpowiednik S4 funkcji UseMethod(). setGeneric() zwraca nazwę funkcji generycznej, która jest wyświetlana po wywołaniu jej na najwyższym poziomie:

setGeneric("area", function(shape) standardGeneric("area"))

Wynik:

[1] "area"

Owiń wywołanie w invisible(), aby ten wiersz nie pojawiał się w wyniku. setMethod("area", "Circle", ...) dodaje następnie metodę dla jednej klasy:

setClass("Circle", slots = c(r = "numeric"))
setClass("Square", slots = c(side = "numeric"))
invisible(setGeneric("area", function(shape) standardGeneric("area")))
setMethod("area", "Circle", function(shape) pi * shape@r^2)
setMethod("area", "Square", function(shape) shape@side^2)
cat(area(new("Circle", r = 1)), area(new("Square", side = 3)))

Wynik:

3.141593 9

Metoda ma takie same argumenty jak jej funkcja generyczna. Gdy funkcja generyczna zawiera ..., metoda może dodać po nich własne argumenty nazwane:

setClass("Circle", slots = c(r = "numeric"))
invisible(setGeneric("describe", function(x, ...) standardGeneric("describe")))
setMethod("describe", "Circle", function(x, ..., digits = 2) {
  paste("circle of area", round(pi * x@r^2, digits))
})
c1 <- new("Circle", r = 2)
print(describe(c1))
print(describe(c1, digits = 4))

Wynik:

[1] "circle of area 12.57"
[1] "circle of area 12.5664"

Wymaga, aby generyczna funkcja już istniała, dlatego plik z setGeneric() jest wczytywany jako pierwszy. Wywołanie dla klasy bez metody kończy się błędem, który podaje sygnaturę:

invisible(setGeneric("area", function(shape) standardGeneric("area")))
setClass("Circle", slots = c(r = "numeric"))
setMethod("area", "Circle", function(shape) pi * shape@r^2)
area(42)

Wynik:

Error: unable to find an inherited method for function ‘area’ for signature ‘shape = "numeric"’
Execution halted
challenge icon

Wyzwanie

Łatwy

Kształty są klasami S4 w trzech plikach. W pliku Shape.R utwórz funkcje generyczne area(shape) i perimeter(shape) za pomocą setGeneric(), opakowane w invisible(). W plikach Circle.R i Square.R zadeklarowane są klasy; dodaj metody area i perimeter dla każdej z nich za pomocą setMethod().

Dostarczony kod odczytuje wiersze circle 2 lub square 3 i wyświetla circle: area 12.57, perimeter 12.57.

Twój kod umieść w plikach Shape.R, Circle.R i Square.R. Plik main.R zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

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

# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  s <- if (p[1] == "circle") new("Circle", r = as.numeric(p[2])) else new("Square", side = as.numeric(p[2]))
  cat(sprintf("%s: area %.2f, perimeter %.2f", p[1], area(s), perimeter(s)), "\n", sep = "")
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator R online