생성자 함수
Coddy R 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 3번째.
R은 S3 객체의 필드를 절대 확인하지 않으므로, 클래스의 모든 객체는 하나의 함수인 생성자로 만들어야 합니다. 관례상 저수준 생성자는 new_와 클래스 이름을 이어 붙인 이름으로 지정합니다. 생성자는 각 필드를 인수로 받고, stopifnot()을 사용하여 타입을 확인한 다음 객체를 반환합니다:
new_money <- function(amount = double(), currency = character()) {
stopifnot(is.double(amount), is.character(currency))
structure(list(amount = amount, currency = currency), class = "money")
}
m <- new_money(9.5, "EUR")
cat(m$amount, m$currency)출력:
9.5 EURstopifnot()는 조건 중 하나라도 TRUE가 아니면 프로그램을 중지하며, 메시지에는 실패한 검사의 이름이 표시됩니다. 잘못된 형식은 나중에 다른 함수가 객체를 사용할 때가 아니라 객체가 생성되는 순간에 감지됩니다:
new_money <- function(amount = double(), currency = character()) {
stopifnot(is.double(amount), is.character(currency))
structure(list(amount = amount, currency = currency), class = "money")
}
m <- new_money("9.5", "EUR")출력:
Error in new_money("9.5", "EUR") : is.double(amount) is not TRUE
Calls: new_money -> stopifnot
Execution halted생성자는 클래스에 대해 structure()를 호출하는 유일한 곳이므로 모든 객체는 같은 순서로 동일한 필드를 가집니다. 많은 객체가 필요한 코드는 이를 루프에서 또는 lapply()와 함께 호출합니다:
new_point <- function(x = 0, y = 0) {
stopifnot(is.numeric(x), is.numeric(y))
structure(list(x = x, y = y), class = "point")
}
pts <- lapply(1:3, function(i) new_point(i, i * i))
for (p in pts) cat(p$x, p$y, "\n")출력:
1 1
2 4
3 9 S3 객체는 반드시 리스트일 필요는 없습니다. 생성자는 일반 벡터에 레이블을 지정하고 추가 정보를 속성으로 저장할 수 있으며, 이것이 R 자체의 factor와 날짜가 작동하는 방식입니다. attr(x, "unit")은 속성을 읽습니다:
new_distance <- function(value = double(), unit = "m") {
stopifnot(is.double(value), is.character(unit))
structure(value, unit = unit, class = "distance")
}
d <- new_distance(c(1.5, 2), "km")
print(attr(d, "unit"))
print(unclass(d)[2] * 1000)출력:
[1] "km"
[1] 2000챌린지
쉬움Book.R에서 생성자 new_book(title, author, pages)를 완성하세요. 이 생성자는 stopifnot()을 사용하여 title과 author가 문자형이고 pages가 숫자형인지 확인한 후, 이 세 필드와 book 클래스를 포함하는 리스트를 반환합니다. 그런 다음 book_label(b)를 완성하세요. 이 함수는 Dune by Frank Herbert, 412 pages를 반환합니다.
제공된 코드는 title;author;pages 형식의 줄을 읽습니다. pages가 숫자로만 이루어져 있으면 숫자로 전달하고, 그렇지 않으면 원래 텍스트로 전달합니다. 각 객체에 대해 book: 과 레이블을 출력하며, 생성자가 중단되면 rejected: 와 제목을 출력합니다.
코드는 Book.R에 작성하세요. main.R에는 제공된 입력/출력 코드가 포함되어 있으며 편집할 수 없습니다.
직접 해보기
source("Book.R")
# 제공된 입력/출력 코드: 있는 그대로 유지
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
p <- strsplit(line, ";")[[1]]
pages <- if (grepl("^[0-9]+$", p[3])) as.numeric(p[3]) else p[3]
b <- tryCatch(new_book(p[1], p[2], pages), error = function(e) NULL)
if (is.null(b)) {
cat("rejected: ", p[1], "\n", sep = "")
} else {
cat(class(b), ": ", book_label(b), "\n", sep = "")
}
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 R 컴파일러