Menu
Coddy logo textTech

Yapıcı Fonksiyonlar

Coddy'nin R Journey'sinin Nesne Tabanlı Programlama bölümünün bir parçası. Ders 3 / 57.

R, bir S3 nesnesinin alanlarını hiçbir zaman denetlemediğinden, bir sınıfın her nesnesi tek bir işlev, yani kurucu tarafından oluşturulmalıdır. Geleneksel olarak düşük düzeyli kurucunun adı new_ ve ardından sınıf adından oluşur. Her alanı bir bağımsız değişken olarak alır, türleri stopifnot() ile denetler ve nesneyi döndürür:

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)

Çıktı:

9.5 EUR

stopifnot(), koşullarından biri TRUE olmadığında programı durdurur ve ileti, başarısız olan denetimi belirtir. Yanlış tür, nesne oluşturulduğu anda yakalanır; başka bir işlev onu kullandığında daha sonra değil:

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

Çıktı:

Error in new_money("9.5", "EUR") : is.double(amount) is not TRUE
Calls: new_money -> stopifnot
Execution halted

Yapıcı, sınıf için structure() işlevini çağıran tek yerdir; bu nedenle her nesne aynı alanlara aynı sırayla sahip olur. Çok sayıda nesneye ihtiyaç duyan kod, bu işlevi bir döngü içinde veya lapply() ile çağırır:

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

Çıktı:

1 1 
2 4 
3 9 

Bir S3 nesnesinin liste olması gerekmez. Bir kurucu, sıradan bir vektöre etiket verebilir ve ek bilgileri öznitelikler olarak saklayabilir; R'nin kendi faktörleri ve tarihleri de bu şekilde çalışır. attr(x, "unit") bir özniteliği okur:

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)

Çıktı:

[1] "km"
[1] 2000
challenge icon

Görev

Kolay

Book.R içindeki new_book(title, author, pages) kurucusunu tamamlayın. stopifnot() ile title ve author değerlerinin karakter, pages değerinin ise sayısal olduğunu denetler ve bu üç alanı ve book sınıfını içeren bir liste döndürür. Ardından, Dune by Frank Herbert, 412 pages döndüren book_label(b) işlevini tamamlayın.

Sağlanan kod, title;author;pages biçimindeki satırları okur. pages yalnızca rakamlardan oluşuyorsa sayı olarak, aksi takdirde özgün metin olarak iletir; her nesne için book: ve etiketi yazdırır, kurucu durduğunda ise rejected: ve başlığı yazdırır.

Kodunuz Book.R içine gelmelidir. main.R, sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.

Kendin dene

source("Book.R")

# Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
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 = "")
  }
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Nesne Tabanlı Programlama bölümündeki tüm dersler

Kendi başına pratik yap: Online R derleyicisi