Closure có trạng thái
Thuộc phần Logic và luồng điều khiển trong hành trình R của Coddy. Bài học 30 trên 64.
Bên trong một hàm, <- tạo một biến cục bộ. Toán tử <<- thay vào đó gán giá trị cho biến cùng tên trong hàm bao quanh, nhờ vậy một closure có thể cập nhật giá trị mà nó đã nắm giữ:
make_counter <- function() {
count <- 0
function() {
count <<- count + 1
count
}
}
next_id <- make_counter()
print(next_id())
print(next_id())
print(next_id())Đầu ra:
[1] 1
[1] 2
[1] 3Mỗi bộ đếm do hàm tạo tạo ra có count riêng, nên chúng không bao giờ ảnh hưởng lẫn nhau:
make_counter <- function() {
count <- 0
function() {
count <<- count + 1
count
}
}
a <- make_counter()
b <- make_counter()
for (i in 1:2) a()
print(a())
print(b())Đầu ra:
[1] 3
[1] 1Với <- thông thường bên trong hàm đóng, phép cập nhật tạo một biến cục bộ mới và biến đó biến mất sau mỗi lần gọi, còn giá trị được lưu trữ không bao giờ thay đổi:
make_broken <- function() {
count <- 0
function() {
count <- count + 1
count
}
}
f <- make_broken()
for (i in 1:2) f()
print(f())Đầu ra:
[1] 1Hàm tạo có thể trả về một danh sách các hàm đóng (closure) dùng chung các biến. Khi kết hợp lại, chúng hoạt động như một đối tượng nhỏ có dữ liệu riêng:
make_wallet <- function(balance) {
list(
add = function(x) balance <<- balance + x,
get = function() balance
)
}
w <- make_wallet(10)
w$add(5)
print(w$get())Đầu ra:
[1] 15Thử thách
DễHoàn thiện make_counter(). Hàm này trả về một hàm, mỗi lần được gọi sẽ tăng biến đếm riêng lên 1 và trả về số đếm mới, bắt đầu từ 1.
Code được cung cấp tạo hai bộ đếm, a và b. Code đọc một danh sách a và b được phân tách bằng dấu phẩy, gọi bộ đếm tương ứng cho mỗi mục và in từng giá trị trả về trên một dòng riêng.
Tự làm thử
make_counter <- function() {
# Viết code của bạn ở đây
function() 0
}
# Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
input <- suppressWarnings(readLines(file("stdin")))
counters <- list(a = make_counter(), b = make_counter())
for (k in strsplit(input[1], ",")[[1]]) cat(counters[[k]](), "\n", sep = "")
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Logic và luồng điều khiển
1Chuỗi chuyên sâu
Chuỗi con với substr()Định dạng với sprintf()Tách và nối chuỗiTìm kiếm trong chuỗiThay thế văn bảnÔn tập: Tạo tên người dùng10Luồng điều khiển nâng cao
Hàm switch()ifelse() dạng vector hóarepeat và breakHàm đệ quyÔn tập: phân loại điểmTự luyện tập: Trình biên dịch R online