Menu
Coddy logo textTech

Closures כאובייקטים

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

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

make_account <- function(balance = 0) {
  deposit <- function(x) balance <<- balance + x
  get_balance <- function() balance
  list(deposit = deposit, get_balance = get_balance)
}
acc <- make_account(100)
acc$deposit(50)
print(acc$get_balance())

פלט:

[1] 150

כל קריאה לפונקציית המפעל מריצה שוב את הגוף שלה, ולכן לכל אובייקט יש משתנים משלו. שינוי של חשבון אחד אינו משפיע על האחר:

make_account <- function(balance = 0) {
  list(deposit = function(x) balance <<- balance + x,
       get_balance = function() balance)
}
ada <- make_account(100)
bo <- make_account(5)
ada$deposit(1)
cat(ada$get_balance(), bo$get_balance())

פלט:

101 5

הנתונים פרטיים. balance אינו איבר ברשימה, ולכן acc$balance הוא NULL והשמה אליו רק מוסיפה איבר לא קשור. הפונקציות ברשימה הן כל הממשק הציבורי של האובייקט:

make_account <- function(balance = 0) {
  list(get_balance = function() balance)
}
acc <- make_account(100)
print(acc$balance)
acc$balance <- 1e6
print(acc$get_balance())

פלט:

NULL
[1] 100

המתודות יכולות לקרוא זו לזו כשהן מוגדרות כפונקציות מקומיות לפני בניית הרשימה. כאן add_many() משתמשת מחדש ב-add():

make_tally <- function() {
  total <- 0
  add <- function(x) total <<- total + x
  add_many <- function(xs) for (x in xs) add(x)
  get <- function() total
  list(add = add, add_many = add_many, get = get)
}
t <- make_tally()
t$add(1)
t$add_many(c(2, 3, 4))
print(t$get())

פלט:

[1] 10
challenge icon

אתגר

קל

השלימו את הפונקציה ליצירת מונה make_counter(start = 0) בקובץ Counter.R. היא שומרת את הערך הנוכחי כפרטי ומחזירה רשימה עם ארבע פונקציות: increment() ו־decrement() משנות את הערך ב־1, reset() מחזירה אותו ל־start, ו־value() מחזירה אותו.

הקוד שסופק קורא את ערך ההתחלה, ואז פקודות +, - או reset, ומדפיס את הערך אחרי כל אחת מהן. בסוף הוא מדפיס את השמות ברשימה שהוחזרה, שצריכה להכיל רק את ארבע הפונקציות.

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

נסו בעצמכם

source("Counter.R")

# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
input <- suppressWarnings(readLines(file("stdin")))
counter <- make_counter(as.numeric(input[1]))
for (cmd in input[-1]) {
  if (cmd == "+") counter$increment()
  if (cmd == "-") counter$decrement()
  if (cmd == "reset") counter$reset()
  cat(cmd, " -> ", counter$value(), "\n", sep = "")
}
cat("fields visible: ", paste(sort(names(counter)), collapse = ", "), "\n", sep = "")
quiz iconבחנו את עצמכם

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

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

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