Menu
Coddy logo textTech

מתודות ועדכון שדות

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

מתודות מופיעות ברשימה methods של setRefClass(). בתוך מתודה, השדות הם שמות רגילים, ו-<<- משנה שדה. במריץ של Coddy, ‏R מדפיסה הודעה על החבילה האופציונלית codetools כשמגדירים מחלקה עם מתודות, לכן יש לעטוף את ההגדרה ב-suppressMessages():

Counter <- suppressMessages(setRefClass("Counter",
  fields = list(count = "numeric"),
  methods = list(
    add = function(n = 1) {
      count <<- count + n
    },
    report = function() paste("count is", count)
  )
))
c1 <- Counter$new(count = 0)
c1$add()
c1$add(5)
print(c1$report())

פלט:

[1] "count is 6"

.self הוא האובייקט שעליו הופעלה המתודה. מתודה שמסתיימת ב-invisible(.self) מחזירה את האובייקט, כך שאפשר לשרשר קריאות:

Counter <- suppressMessages(setRefClass("Counter",
  fields = list(count = "numeric"),
  methods = list(
    add = function(n = 1) {
      count <<- count + n
      invisible(.self)
    }
  )
))
c1 <- Counter$new(count = 0)
c1$add(2)$add(3)$add(4)
print(c1$count)

פלט:

[1] 9

המתודה initialize מופעלת בתוך $new(). initFields(...) מגדירה את השדות שהועברו; לאחר מכן המתודה יכולה לתת ערכי ברירת מחדל לשדות האחרים. מתודות קוראות זו לזו לפי שם:

Account <- suppressMessages(setRefClass("Account",
  fields = list(owner = "character", balance = "numeric"),
  methods = list(
    initialize = function(...) {
      initFields(...)
      if (length(balance) == 0) balance <<- 0
      invisible(.self)
    },
    deposit = function(x) balance <<- balance + x,
    deposit_twice = function(x) {
      deposit(x)
      deposit(x)
    }
  )
))
a <- Account$new(owner = "Ada")
a$deposit_twice(10)
print(a$balance)

פלט:

[1] 20

בתוך מתודה, השמה רגילה באמצעות <- לשם של שדה יוצרת משתנה מקומי בשם הזה ומשאירה את השדה ללא שינוי. השתמשו ב־<<- בכל שינוי של שדה:

Counter <- suppressMessages(setRefClass("Counter",
  fields = list(count = "numeric"),
  methods = list(
    broken = function() count <- count + 1,
    working = function() count <<- count + 1
  )
))
c1 <- Counter$new(count = 0)
c1$broken()
c1$broken()
c1$working()
print(c1$count)

פלט:

[1] 1
challenge icon

אתגר

קל

השלימו את מחלקת הייחוס Stack בקובץ Stack.R. הפריטים שלה נשמרים בשדה items (מסוג character, כשהפריט העליון אחרון), ויש לה ארבע שיטות:

  • push(x) מוסיפה את x לראש ומחזירה invisible(.self), כך שאפשר לשרשר קריאות ל־push;
  • pop() מסירה ומחזירה את הפריט העליון, או מחזירה את nothing כשהמחסנית ריקה;
  • peek() מחזירה את הפריט העליון בלי להסיר אותו, או את nothing;
  • size() מחזירה את מספר הפריטים.

ההגדרה כבר עטופה ב־suppressMessages(). הקוד שסופק קורא פקודות push a b,‏ pop ו־peek, ואז דוחף שני פריטים נוספים בקריאה משורשרת אחת ומדפיס את הגודל.

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

נסו בעצמכם

source("Stack.R")

# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
input <- suppressWarnings(readLines(file("stdin")))
s <- Stack$new()
for (cmd in input) {
  if (startsWith(cmd, "push ")) {
    items <- strsplit(substring(cmd, 6), " ")[[1]]
    for (it in items) s$push(it)
  } else if (cmd == "pop") {
    cat("popped ", s$pop(), "\n", sep = "")
  } else if (cmd == "peek") {
    cat("top ", s$peek(), "\n", sep = "")
  }
}
s$push("x")$push("y")
cat("size after two chained pushes: ", s$size(), "\n", sep = "")
quiz iconבחנו את עצמכם

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

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

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