Hàm generic và UseMethod
Thuộc phần Lập trình hướng đối tượng trong hành trình R của Coddy. Bài học 7 trên 57.
Một hàm tổng quát là hàm có phần thân là UseMethod("name"). Khi được gọi, hàm sẽ xem lớp của đối số đầu tiên rồi gọi phương thức name.class. print() và format() hoạt động theo cách này; bạn cũng có thể tự viết hàm tổng quát:
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))Đầu ra:
[1] "Rex says woof"
[1] "Tom says meow"Bên gọi viết một lời gọi, rồi mỗi đối tượng trả lời theo cách riêng. Đây là tính đa hình: đoạn code duyệt qua một danh sách hỗn hợp không cần có if cho từng lớp:
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")Đầu ra:
Rex says woof
Tom says meow
Bo says woof Một phương thức nhận các đối số của hàm generic. Thêm tham số ... vào hàm generic để các phương thức có thể nhận thêm đối số riêng, chẳng hạn như digits cho hình tròn:
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))Đầu ra:
[1] 9
[1] 3.14
[1] 3.1416UseMethod() chuyển lời gọi cho phương thức và không bao giờ quay lại: giá trị mà phương thức trả về chính là kết quả của hàm tổng quát, còn code phía sau UseMethod() sẽ không chạy. Vì vậy, hàm tổng quát chỉ gồm một dòng:
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))Đầu ra:
[1] 10Thử thách
DễCác hình được chia thành ba tệp. Hoàn thiện hàm tổng quát area() trong Shape.R, rồi thêm các phương thức area.circle() (pi nhân với bán kính bình phương) trong Circle.R và area.rectangle() (chiều rộng nhân với chiều cao) trong Rectangle.R. Các hàm khởi tạo đã được cung cấp.
Code được cung cấp đọc các dòng circle 2 hoặc rectangle 3 4 và in ra lớp cùng diện tích của mỗi hình với hai chữ số thập phân: circle: 12.57.
Code của bạn nằm trong Shape.R, Circle.R và Rectangle.R. main.R chứa code đầu vào/đầu ra được cung cấp và không thể chỉnh sửa.
Tự làm thử
source("Shape.R")
source("Circle.R")
source("Rectangle.R")
# Đoạn code đầu vào/đầu ra đã được cung cấp: giữ nguyên
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 = "")
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Kiến thức cơ bản về S3
Làm việc với tệpDanh sách với một lớpHàm khởi tạoPhương thức in ra và định dạngTrình xác thực và hàm hỗ trợÔn tập: nhiệt độ4Tính đóng gói trong R
Closure dưới dạng đối tượngMôi trường dưới dạng đối tượngHàm truy cậpBảo vệ trạng tháiÔn tập: đồng hồ tính phí đỗ xe2S3, hàm generic và phương thức
Hàm generic và UseMethodPhương thức mặc địnhPhương thức cho hàm generic cơ sởCơ bản về NextMethodÔn tập: diện tích hình5Các lớp S4
Định nghĩa lớp S4Slot và quyền truy cậpKiểm tra tính hợp lệPhương thức showÔn tập: Danh mục sản phẩmTự luyện tập: Trình biên dịch R online