Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

دوال المُنشئ

جزء من قسم البرمجة كائنية التوجه في رحلة R على Coddy. الدرس 3 من 57.

نظرًا لأن R لا يتحقق أبدًا من حقول كائن S3، يجب إنشاء كل كائن من فئة ما بواسطة دالة واحدة، وهي البانية. convention تُسمى البانية منخفضة المستوى 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 EUR

stopifnot() يوقف البرنامج عندما لا يكون أحد شروطه 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. تقرأ 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
challenge icon

التحدي

سهل

أكمل المُنشئ new_book(title, author, pages) في Book.R. فهو يتحقق باستخدام stopifnot() من أن title وauthor من النوع النصي وأن pages من النوع الرقمي، ثم يعيد قائمة تحتوي على هذه الحقول الثلاثة وعلى الفئة book. بعد ذلك أكمل book_label(b)، التي تعيد Dune by Frank Herbert, 412 pages.

يقرأ الكود المُ supplied الأسطر title;author;pages. ويمرر pages كرقم عندما يتكون من أرقام، وكالنص الأصلي بخلاف ذلك، ثم يطبع book: والتسمية لكل كائن، ويطبع rejected: والعنوان عندما يتوقف المُنشئ.

ضع كودك في Book.R. يحتوي main.R على كود الإدخال/الإخراج المُ supplied ولا يمكن تعديله.

جرّب بنفسك

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 = "")
  }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم R عبر الإنترنت