Menu
Coddy logo textTech

מאמתים ופונקציות עזר

חלק מהיחידה תכנות מונחה עצמים במסלול ה-R של Coddy. שיעור 5 מתוך 57.

הבנאי בודק טיפוסים; מאמת בודק ערכים. לפי המוסכמה, validate_money() מקבלת אובייקט, קוראת ל־stop() עם הודעה ברורה עבור כל כלל שהוא מפר, ומחזירה את האובייקט כשהכול תקין. call. = FALSE מונע מהקריאה לפונקציה להופיע בהודעה:

new_money <- function(amount = double(), currency = character()) {
  stopifnot(is.double(amount), is.character(currency))
  structure(list(amount = amount, currency = currency), class = "money")
}
validate_money <- function(x) {
  if (x$amount < 0) stop("amount must not be negative", call. = FALSE)
  if (nchar(x$currency) != 3) stop("currency must have 3 letters", call. = FALSE)
  x
}
m <- validate_money(new_money(-5, "EUR"))

פלט:

Error: amount must not be negative
Execution halted

הפונקציית עזר היא הפונקציה שקוד אחר קורא לה. היא נקראת על שם המחלקה, ממירה את הקלט שלה לטיפוסים המתאימים, ממלאת ערכי ברירת מחדל ומעבירה את התוצאה דרך הבנאי והמאמת:

new_money <- function(amount = double(), currency = character()) {
  stopifnot(is.double(amount), is.character(currency))
  structure(list(amount = amount, currency = currency), class = "money")
}
validate_money <- function(x) {
  if (x$amount < 0) stop("amount must not be negative", call. = FALSE)
  x
}
money <- function(amount, currency = "EUR") {
  validate_money(new_money(as.double(amount), toupper(currency)))
}
m <- money("12", "usd")
cat(m$amount, m$currency)

פלט:

12 USD

קוד שקורא קלט מהמשתמש תופס את השגיאות של המאמת באמצעות tryCatch() ומציג את conditionMessage(e), הטקסט שמועבר אל stop():

validate_age <- function(x) {
  if (x$years < 0) stop("age must not be negative", call. = FALSE)
  if (x$years > 150) stop("age is too large", call. = FALSE)
  x
}
age <- function(years) validate_age(structure(list(years = as.double(years)), class = "age"))
for (input in c("30", "-2", "200")) {
  result <- tryCatch(paste("ok", age(input)$years), error = function(e) conditionMessage(e))
  cat(result, "\n")
}

פלט:

ok 30 
age must not be negative 
age is too large 

לכל אחת משלוש הפונקציות יש תפקיד אחד. new_money() קפדנית ומהירה, ומיועדת לקוד שבו כבר נעשה שימוש בטיפוסים הנכונים. validate_money() מכילה את הכללים לגבי ערכים, שעשויים להיות איטיים לבדיקה או רבים. money() ידידותית, והיא הפונקציה שבה משתמש שאר התוכנית:

new_money()       # טיפוסים בלבד; בונה את האובייקט באמצעות structure()
validate_money()  # כללים לערכים; מפעיל stop() עם הודעה, אחרת מחזיר את x
money()           # ממיר את הקלט, ואז מפעיל validate_money(new_money(...))
challenge icon

אתגר

קל

new_score(points, max) בקובץ Score.R בונה אובייקט score. השלימו את הפונקציות האחרות באותו קובץ:

  • validate_score(x) עוצרת עם points must not be negative, max must be positive או points must not exceed max, לפי הסדר הזה, ואחרת מחזירה את x.
  • score(points, max = 100) ממירה את שני הארגומנטים באמצעות as.double() ומחזירה validate_score(new_score(...)).
  • format.score(x, ...) מחזירה 45/50 (90%), כשהאחוז מעוגל למספר שלם.

השתמשו ב-call. = FALSE בכל קריאה ל-stop(). הקוד שסופק קורא את השורה 45 50, מדפיס את הציון המעוצב, או את error: ואת הודעת השגיאה.

הקוד שלכם ייכתב ב-Score.R. הקובץ main.R מכיל את קוד הקלט/פלט שסופק, ואי אפשר לערוך אותו.

נסו בעצמכם

source("Score.R")

# קוד קלט/פלט שסופק: יש להשאיר אותו כפי שהוא
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  s <- tryCatch(score(p[1], p[2]), error = function(e) conditionMessage(e))
  if (is.character(s)) cat("error: ", s, "\n", sep = "") else cat(format(s), "\n", sep = "")
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר R אונליין