Các x
đó là bên trong hàm nặc danh là không các x
trong môi trường toàn cầu (không gian làm việc của bạn). Đây là bản sao của x
, địa phương cho chức năng ẩn danh. Nó không phải là quá đơn giản để nói rằng R bản sao đối tượng trong các cuộc gọi chức năng; R sẽ cố gắng để không sao chép nếu nó có thể, mặc dù một khi bạn sửa đổi một cái gì đó R đã sao chép các đối tượng.
Như @DWin chỉ ra, phiên bản này sao chép của x
đó đã được sửa đổi là trả về bởi các sapply()
cuộc gọi, đầu ra tuyên bố của bạn không phải là những gì tôi nhận được:
> x <- c(1:10)
> print(x)
[1] 1 2 3 4 5 6 7 8 9 10
> sapply(1:10,function(i){
+ x[i] = 4
+ })
[1] 4 4 4 4 4 4 4 4 4 4
> print(x)
[1] 1 2 3 4 5 6 7 8 9 10
Rõ ràng, các mã đã gần như những gì bạn nghĩ rằng nó sẽ. Vấn đề là đầu ra từ sapply()
không được gán cho một đối tượng và do đó được in và từ đó bị loại bỏ.
Lý do bạn mã thậm chí hoạt động là do các quy tắc phạm vi của R. Bạn thực sự nên chuyển sang một hàm làm đối số cho bất kỳ đối tượng nào mà hàm cần. Tuy nhiên, nếu R không thể tìm thấy một đối tượng cục bộ với hàm, nó sẽ tìm kiếm môi trường cha mẹ cho một đối tượng khớp với tên, và sau đó là cha của môi trường đó nếu thích hợp, cuối cùng nhấn môi trường toàn cục, vùng làm việc. Vì vậy, mã của bạn hoạt động vì nó cuối cùng tìm thấy một x
để làm việc với, nhưng đã được sao chép ngay lập tức, bản sao đó được trả lại vào cuối cuộc gọi sapply()
.
Quá trình sao chép này mất nhiều thời gian và bộ nhớ trong nhiều trường hợp. Đây là một trong những lý do mọi người nghĩ rằng các vòng for
chậm trong R; họ không phân bổ lưu trữ cho một đối tượng trước khi điền nó với một vòng lặp. Nếu bạn không cấp phát bộ nhớ, R phải sửa đổi/sao chép đối tượng để thêm kết quả tiếp theo của vòng lặp.
Một lần nữa, mặc dù nó không phải lúc nào cũng đơn giản, ở khắp mọi nơi trong R, ví dụ với môi trường, nơi một bản sao của một môi trường thực sự chỉ đề cập đến phiên bản gốc:
> a <- new.env()
> a
<environment: 0x1af2ee0>
> b <- 4
> assign("b", b, env = a)
> a$b
[1] 4
> c <- a ## copy the environment to `c`
> assign("b", 7, env = c) ## assign something to `b` in env `c`
> c$b ## as expected
[1] 7
> a$b ## also changed `b` in `a` as `a` and `c` are actually the same thing
[1] 7
Nếu bạn hiểu những loại của mọi thứ, đọc hướng dẫn sử dụng R Language Definition bao gồm nhiều chi tiết về những gì diễn ra dưới mui xe trong R.
Cảm ơn! Nhưng tại sao không ai viết mã như vậy trong R? Có một số rủi ro tiềm ẩn hay chỉ là một quy ước? Tôi nghĩ rằng nó là khá bình thường để sửa đổi các đối tượng toàn cầu trong một chức năng trong các ngôn ngữ khác. –
Trong các chức năng ngôn ngữ chức năng không thể có tác dụng phụ. R không phải là nghiêm ngặt nhưng nó vẫn đúng rằng R chức năng giới hạn tác dụng phụ. Nó tốt hơn để làm việc theo cách nó được dự định sẽ được sử dụng hơn là cố gắng viết như thể bạn đang viết bằng một ngôn ngữ khác. Có một số hệ thống đối tượng (S3, S4, Lớp tham khảo). S3 được sử dụng phổ biến nhất. S4 phức tạp hơn nhiều. Các lớp tham chiếu là một bổ sung gần đây. Bạn có thể muốn khám phá các Lớp tham khảo, đặc biệt. Ngoài ra còn có một số gói người dùng đóng góp cung cấp các mô hình khác nhau: proto và R.oo (và có thể cả những người khác). –
@Spirit Plus bạn có thể sử dụng 'parent.frame (3)' thay vì '.GlobalEnv' để lưu trữ x trong một đóng cửa trong đó sapply được chạy, những gì sẽ được an toàn hơn nhiều. (Tại sao 3? 1 khung chức năng ẩn danh, khung 2 cực kỳ, bao vây 3 mặt) – mbq