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אתגר
קלהשלימו את המפעל 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 = "")
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות S3
עבודה עם קבציםרשימות עם מחלקהפונקציות בנאימתודות print ו-formatמאמתים ופונקציות עזרחזרה – טמפרטורותתרגלו בעצמכם: קומפיילר R אונליין