Menu
CoddyTech

Melindungi state

Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan R di Coddy. Pelajaran 20 dari 57.

Setter adalah satu-satunya tempat nilai dapat berubah, jadi di sinilah aturan diberlakukan. Setter memeriksa terlebih dahulu dan memanggil stop() sebelum apa pun diubah, sehingga object tetap valid:

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())

Output:

insufficient funds / 50

lockBinding("rate", e) membuat satu variabel dalam sebuah environment hanya bisa dibaca. Jika kamu menetapkan nilai baru padanya setelah itu, akan terjadi error, sedangkan variabel lainnya tetap bisa ditulis:

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")

Output:

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

lockEnvironment(e) mencegah penambahan variabel baru. Dengan bindings = TRUE, fungsi ini juga mengunci semua variabel yang sudah ada, sehingga seluruh object menjadi hanya-baca:

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")
}

Output:

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

local() menjalankan kode di environment baru dan mengembalikan nilai terakhirnya. Fungsi pembantu yang didefinisikan di dalamnya tetap tersembunyi. Dengan cara ini, sebuah file dapat menjaga fungsi tetap privat meskipun source() memasukkan semua hal lainnya ke environment global:

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

Output:

[1] 12.57
[1] FALSE
challenge icon

Tantangan

Mudah

Lengkapi fungsi factory make_account(owner) di Account.R. Saldo dimulai dari 0 dan riwayat privat mencatat setiap perubahan sebagai +50 atau -20. List yang dikembalikan memiliki empat fungsi:

  • deposit(x) berhenti dengan amount must be positive kecuali jika x lebih besar dari 0;
  • withdraw(x) berhenti dengan amount must be positive atau insufficient funds;
  • balance() mengembalikan saldo;
  • history() mengembalikan riwayat sebagai vektor karakter.

Lakukan pemeriksaan sebelum mengubah apa pun dan gunakan call. = FALSE. Kode yang disediakan membaca pemilik, lalu baris dep 50 atau wd 20, mencetak ok atau error: beserta pesannya untuk setiap baris, mencoba mengubah salinan riwayat, lalu mencetak saldo dan riwayat.

Tulis kodemu di Account.R. main.R berisi kode input/output yang disediakan dan tidak boleh diedit.

Coba sendiri

source("Account.R")

# Kode input/output yang disediakan: biarkan apa adanya
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 iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Pemrograman Berorientasi Object

Latihan sendiri: Compiler R online