Menu
Coddy logo textTech

Umgebungen als Objekte

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

Eine Umgebung ist eine Menge benannter Werte, ähnlich wie eine Liste, die mit new.env() erstellt wird. Der Unterschied besteht darin, dass eine Umgebung niemals kopiert wird: Jede Variable, die auf sie verweist, sieht dasselbe Objekt, sodass eine Änderung über einen Namen durch alle Namen sichtbar ist:

e <- new.env()
e$count <- 1
alias <- e
alias$count <- 99
print(e$count)
l <- list(count = 1)
copy <- l
copy$count <- 99
print(l$count)

Ausgabe:

[1] 99
[1] 1

Eine Funktion, die eine Umgebung erhält, ändert das Objekt des Aufrufers. Sie muss nichts zurückgeben, und der Aufrufer weist kein Ergebnis zu:

deposit <- function(acc, x) acc$balance <- acc$balance + x
acc <- new.env()
acc$balance <- 10
deposit(acc, 5)
deposit(acc, 5)
print(acc$balance)

Ausgabe:

[1] 20

assign(), get() und exists() arbeiten mit einem in einer Variable gespeicherten Namen, und ls() listet die Namen in einer Umgebung in sortierter Reihenfolge auf:

e <- new.env()
for (fruit in c("pear", "apple")) assign(fruit, nchar(fruit), envir = e)
print(ls(e))
print(get("pear", envir = e))
print(exists("kiwi", envir = e))

Ausgabe:

[1] "apple" "pear" 
[1] 4
[1] FALSE

Eine Umgebung mit einem Klassenattribut ist ein S3-Objekt mit Referenzsemantik: Seine Methoden funktionieren wie gewohnt, und Funktionen, die es ändern, tun dies direkt:

new_wallet <- function(coins = 0) {
  w <- new.env()
  w$coins <- coins
  class(w) <- "wallet"
  w
}
print.wallet <- function(x, ...) {
  cat("wallet with", x$coins, "coins\n")
  invisible(x)
}
spend <- function(w, n) w$coins <- w$coins - n
w <- new_wallet(10)
spend(w, 3)
w

Ausgabe:

wallet with 7 coins
challenge icon

Aufgabe

Einfach

Ein Inventar ist eine Umgebung der Klasse inventory mit einer Variable, items, einem benannten numerischen Vektor des Bestands. Vervollständige Inventory.R:

  • new_inventory() erstellt die Umgebung mit einem leeren items (c() ist ausreichend) und der Klasse.
  • add_stock(inv, item, n) addiert n zum Bestand des Elements, wobei für ein neues Element bei 0 begonnen wird.
  • take_stock(inv, item, n) entfernt n und gibt TRUE zurück, wenn genügend Bestand vorhanden ist; andernfalls wird nichts geändert und FALSE zurückgegeben.
  • stock_of(inv, item) gibt den Bestand zurück, bei einem unbekannten Element 0.

Die Funktionen ändern das Inventar direkt und geben es nicht zurück. Der bereitgestellte Code liest die Befehle add apple 5 und take apple 2, gibt das Ergebnis jedes take-Befehls aus und anschließend jedes Element in alphabetischer Reihenfolge.

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

Probier es selbst

source("Inventory.R")

# Gelieferter Input/Output-Code: belasse ihn wie er ist
input <- suppressWarnings(readLines(file("stdin")))
inv <- new_inventory()
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  n <- as.numeric(p[3])
  if (p[1] == "add") add_stock(inv, p[2], n)
  if (p[1] == "take") cat("take ", p[2], ": ", if (take_stock(inv, p[2], n)) "ok" else "not enough", "\n", sep = "")
}
for (item in sort(names(inv$items))) cat(item, ": ", stock_of(inv, item), "\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