Menu
Coddy logo textTech

Zustand schützen

Teil des Abschnitts Objektorientierte Programmierung der R-Journey von Coddy. Lektion 20 von 57.

Ein Setter ist die einzige Stelle, an der sich ein Wert ändern kann, daher ist dies der Ort, an dem die Regeln durchgesetzt werden. Er prüft zuerst und ruft stop() auf, bevor irgendetwas geändert wird, und das Objekt bleibt gültig:

make_account <- function(balance = 0) {
  withdraw <- function(x) {
    if (x <= 0) stop("amount must be positive", call. = FALSE)
    if (x > balance) stop("insufficient funds", call. = FALSE)
    balance <<- balance - x
  }
  list(withdraw = withdraw, balance = function() balance)
}
acc <- make_account(50)
msg <- tryCatch(acc$withdraw(80), error = function(e) conditionMessage(e))
cat(msg, "/", acc$balance())

Ausgabe:

insufficient funds / 50

lockBinding("rate", e) macht eine Variable einer Umgebung schreibgeschützt. Eine anschließende Zuweisung ist ein Fehler, während die anderen Variablen weiterhin beschreibbar bleiben:

loan <- new.env()
loan$rate <- 0.05
loan$owed <- 1000
lockBinding("rate", loan)
loan$owed <- 900
msg <- tryCatch({ loan$rate <- 0; "changed" }, error = function(e) conditionMessage(e))
cat(msg, "\n")
cat(loan$rate, loan$owed, "\n")

Ausgabe:

cannot change value of locked binding for 'rate' 
0.05 900 

lockEnvironment(e) verhindert, dass neue Variablen hinzugefügt werden. Mit bindings = TRUE wird außerdem jede vorhandene Variable gesperrt, wodurch das gesamte Objekt schreibgeschützt wird:

cfg <- new.env()
cfg$theme <- "dark"
lockEnvironment(cfg, bindings = TRUE)
for (step in c("change", "add")) {
  msg <- tryCatch({
    if (step == "change") cfg$theme <- "light" else cfg$size <- 12
    "done"
  }, error = function(e) conditionMessage(e))
  cat(step, ":", msg, "\n")
}

Ausgabe:

change : cannot change value of locked binding for 'theme' 
add : cannot add bindings to a locked environment 

local() führt Code in einer neuen Umgebung aus und gibt dessen letzten Wert zurück. Innerhalb definierte Hilfsfunktionen bleiben verborgen. So kann eine Datei eine Funktion privat halten, obwohl source() alles andere in die globale Umgebung einfügt:

circle_area <- local({
  square <- function(x) x * x
  function(r) pi * square(r)
})
print(round(circle_area(2), 2))
print(exists("square"))

Ausgabe:

[1] 12.57
[1] FALSE
challenge icon

Aufgabe

Einfach

Vervollständige die Factory make_account(owner) in Account.R. Der Kontostand beginnt bei 0, und eine private Historie zeichnet jede Änderung als +50 oder -20 auf. Die zurückgegebene Liste enthält vier Funktionen:

  • deposit(x) bricht mit amount must be positive ab, sofern x nicht größer als 0 ist;
  • withdraw(x) bricht mit amount must be positive oder insufficient funds ab;
  • balance() gibt den Kontostand zurück;
  • history() gibt die Historie als Zeichenvektor zurück.

Prüfe alles, bevor du etwas änderst, und verwende call. = FALSE. Der bereitgestellte Code liest den Besitzer ein, anschließend Zeilen wie dep 50 oder wd 20, gibt für jede Zeile ok oder error: und die Nachricht aus, versucht, eine Kopie der Historie zu ändern, und gibt den Kontostand sowie die Historie aus.

Dein Code gehört in Account.R. main.R enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.

Probier es selbst

source("Account.R")

# Mitgelieferter Ein-/Ausgabecode: belasse ihn unverändert
input <- suppressWarnings(readLines(file("stdin")))
acc <- make_account(input[1])
for (line in input[-1]) {
  p <- strsplit(line, " ")[[1]]
  amount <- as.numeric(p[2])
  msg <- tryCatch({
    if (p[1] == "dep") acc$deposit(amount) else acc$withdraw(amount)
    "ok"
  }, error = function(e) paste("error:", conditionMessage(e)))
  cat(line, ": ", msg, "\n", sep = "")
}
h <- acc$history()
h[1] <- "tampered"
cat("balance: ", acc$balance(), "\n", sep = "")
cat("history: ", paste(acc$history(), collapse = ", "), "\n", sep = "")
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-R-Compiler