Menu
Coddy logo textTech

Podstawy NextMethod

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

Wewnątrz metody NextMethod() wywołuje następną metodę dla tego samego generyka, z tymi samymi argumentami. Dla obiektu z jedną klasą następną metodą jest metoda domyślna, więc metoda może ponownie wykorzystać ogólną odpowiedź i ją uzupełnić:

describe <- function(x) UseMethod("describe")
describe.default <- function(x) paste("an object with", length(x), "fields")
describe.task <- function(x) paste0(NextMethod(), ", titled ", x$title)
t <- structure(list(title = "Buy milk", done = FALSE), class = "task")
print(describe(t))

Wynik:

[1] "an object with 2 fields, titled Buy milk"

Obiekt może mieć kilka klas w wektorze, na przykład c("urgent", "task"). Wybór metody sprawdza je po kolei, a NextMethod() w pierwszej metodzie przechodzi do metody dla następnej klasy:

describe <- function(x) UseMethod("describe")
describe.task <- function(x) paste("task:", x$title)
describe.urgent <- function(x) paste("URGENT", NextMethod())
fix <- structure(list(title = "Fix the leak"), class = c("urgent", "task"))
print(describe(fix))

Wynik:

[1] "URGENT task: Fix the leak"

NextMethod() przekazuje dalej każdy argument otrzymany przez metodę, w tym dodatkowe, takie jak sep. Następna metoda widzi te same wartości, bez konieczności ponownego ich wymieniania:

label <- function(x, sep = ": ") UseMethod("label")
label.default <- function(x, sep = ": ") paste0("item", sep, x$name)
label.box <- function(x, sep = ": ") paste0("[", NextMethod(), "]")
b <- structure(list(name = "tools"), class = "box")
print(label(b))
print(label(b, sep = " = "))

Wynik:

[1] "[item: tools]"
[1] "[item = tools]"

Base R używa NextMethod(), aby zachować klasę po wybraniu podwektora. Domyślny operator [ usuwa klasę, więc metoda "[.percent" pozwala wykonać tę operację i przywraca klasę:

format.percent <- function(x, ...) paste0(unclass(x) * 100, "%")
"[.percent" <- function(x, i) structure(NextMethod(), class = "percent")
p <- structure(c(0.1, 0.25, 0.5), class = "percent")
print(format(p[2:3]))

Wynik:

[1] "25%" "50%"
challenge icon

Wyzwanie

Łatwy

Zadania i pilne zadania to dwie klasy w dwóch plikach. W Task.R uzupełnij funkcję generyczną describe(), metodę domyślną, która zwraca an item, oraz describe.task(), która zwraca an item: Buy milk, wywołując NextMethod() i dodając tytuł. W Urgent.R uzupełnij describe.urgent(), która zwraca URGENT an item: Fix bug, wywołując NextMethod().

Konstruktory są już podane: pilne zadanie ma klasę c("urgent", "task"). Dostarczony kod odczytuje wiersze task Buy milk, urgent Fix bug lub dowolne inne słowo z tytułem, które staje się obiektem tej klasy, i wypisuje describe() dla każdego z nich.

Twój kod umieść w plikach Task.R i Urgent.R. main.R zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

source("Task.R")
source("Urgent.R")

# Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  kind <- sub(" .*", "", line)
  title <- sub("^[a-z]+ ", "", line)
  t <- if (kind == "urgent") new_urgent(title) else if (kind == "task") new_task(title) else structure(list(title = title), class = kind)
  cat(describe(t), "\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