Menu
CoddyTech

Создание обобщений

Часть раздела Объектно-ориентированное программирование путешествия по R на Coddy. Урок 27 из 57.

Дженерик S4 создаётся с помощью setGeneric(). Его тело функции — standardGeneric("name"), аналог UseMethod() в S4. setGeneric() возвращает имя дженерика, которое выводится при вызове на верхнем уровне:

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

Вывод:

[1] "area"

Оберни вызов в invisible(), чтобы эта строка не попала в вывод. setMethod("area", "Circle", ...) затем добавляет метод для одного класса:

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

Вывод:

3.141593 9

Метод имеет те же аргументы, что и его обобщённая функция. Если у обобщённой функции есть ..., метод может добавить собственные именованные аргументы после них:

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

Вывод:

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

Для работы setMethod() обобщённая функция должна уже существовать, поэтому сначала загружается файл с setGeneric(). Вызов для класса без метода завершается ошибкой, в которой указана сигнатура:

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

Вывод:

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

Задание

Легко

Фигуры — это классы S4 в трёх файлах. В Shape.R создайте обобщённые функции area(shape) и perimeter(shape) с помощью setGeneric(), обернув их в invisible(). В Circle.R и Square.R объявляются классы; добавьте для каждого методы area и perimeter с помощью setMethod().

Предоставленный код читает строки circle 2 или square 3 и выводит circle: area 12.57, perimeter 12.57.

Ваш код нужно разместить в Shape.R, Circle.R и Square.R. В main.R находится предоставленный код ввода/вывода, и его нельзя редактировать.

Попробуйте сами

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

# Предоставленный код ввода-вывода: оставьте его без изменений
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 iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор R