<<-
là hữu ích nhất kết hợp với đóng cửa để duy trì trạng thái. Đây là một phần trong bài báo gần đây của tôi:
Một bao đóng là một chức năng được viết bởi một chức năng khác. Các bao đóng được gọi như vậy vì chúng bao quanh môi trường của hàm cha và có thể truy cập tất cả các biến và tham số trong hàm đó. Điều này rất hữu ích vì nó cho phép chúng ta có hai cấp độ tham số. Một mức tham số (cha) kiểm soát cách thức hoạt động của chức năng. Các cấp độ khác (trẻ em) làm công việc. Ví dụ sau đây cho thấy làm thế nào có thể sử dụng ý tưởng này để tạo ra một họ các hàm năng lượng. Hàm cha ( power
) tạo ra các hàm con ( square
và cube
) thực sự làm công việc khó khăn.
power <- function(exponent) {
function(x) x ^ exponent
}
square <- power(2)
square(2) # -> [1] 4
square(4) # -> [1] 16
cube <- power(3)
cube(2) # -> [1] 8
cube(4) # -> [1] 64
Khả năng quản lý các biến ở hai cấp độ cũng giúp duy trì trạng thái trên các lệnh gọi hàm bằng cách cho phép một hàm sửa đổi các biến trong môi trường của cha mẹ của nó. Chìa khóa để quản lý các biến ở các cấp độ khác nhau là toán tử gán mũi tên kép <<-
. Không giống như phép gán mũi tên đơn ( <-
) thông thường luôn hoạt động ở cấp độ hiện tại, toán tử mũi tên kép có thể sửa đổi các biến ở cấp độ cha.
Điều này cho phép duy trì bộ đếm ghi lại số lần hàm được gọi, như ví dụ sau đây cho thấy. Mỗi lần new_counter
chạy, nó tạo ra một môi trường, khởi tạo bộ đếm i
trong môi trường này và sau đó tạo một hàm mới.
new_counter <- function() {
i <- 0
function() {
# do something useful, then ...
i <<- i + 1
i
}
}
Các chức năng mới là một đóng cửa, và môi trường của nó là môi trường kèm theo. Khi đóng counter_one
và counter_two
được chạy, mỗi cái sẽ sửa đổi bộ đếm trong môi trường kèm theo của nó và sau đó trả về số hiện tại.
counter_one <- new_counter()
counter_two <- new_counter()
counter_one() # -> [1] 1
counter_one() # -> [1] 2
counter_two() # -> [1] 1