دوال المُنشئ
جزء من قسم البرمجة كائنية التوجه في رحلة 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 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. تقرأ 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التحدي
سهلأكمل المُنشئ 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 = "")
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات S3
التعامل مع الملفاتالقوائم باستخدام فئةدوال المُنشئأساليب الطباعة والتنسيقأدوات التحقق والمساعدةمراجعة - درجات الحرارة2S3 الدوال العامة والطرق
الدوال العامة وUseMethodالطرق الافتراضيةطرق الدوال العامة الأساسيةأساسيات NextMethodمراجعة - مساحات الأشكالتدرّب بنفسك: مترجم R عبر الإنترنت