2013-05-12 14 views
7

Sử dụng một ví dụ từ Programming Chris Smith F # 3.0:Tại sao Fsharp Interactive cho phép các biến có thể thay đổi được chụp bằng cách đóng?

let invalidUseOfMutable() = 
    let mutable x = 0 
    let incrementX() = x <- x + 1 
    incrementX() 
    x;; 

này không như mong đợi:

lỗi FS0407: Biến thể thay đổi 'x' được sử dụng một cách hợp lệ. Biến không thể thay đổi được bằng cách đóng.

Bây giờ cắt và dán các cơ quan chức năng vào FSharp Interactive:

let mutable x = 0 
let incrementX() = x <- x + 1 
incrementX() 
x;; 

Và nó hoạt động!

val nó: int = 1

Tại sao?

+0

Xin chào, nó không tạo ra đóng cửa khi bạn chỉ chạy mã body.use: let x = ref 0; let incrementX() = x: =! x + 1; xem Đóng cửa: http: //msdn.microsoft.com/en-us/library/dd233186.aspx – kwingho

+0

Lưu ý rằng trình biên dịch cũng không phản đối phần thân của hoạt động theo cách riêng của nó. –

Trả lời

8

Câu trả lời ngắn gọn: không phải vì fsi, đó là vì có thể thay đổi được toàn cục.

Long trả lời:

Đối với một (không có thể thay đổi) chụp bình thường, thực hiện khôn ngoan giá trị bắt được sao chép vào các đối tượng chức năng, do đó nếu bạn quay trở lại chức năng này và sử dụng nó ngoài phạm vi trong đó nó đã được xác định, mọi thứ đều hoạt động tốt.

let pureAddOne() = 
    let x = 1 
    let f y = x + y // the value 1 is copied into the function object 
    f 

let g = pureAddOne() 
g 3 // x is now out of scope, but its value has been copied and can be used 

Mặt khác, để nắm bắt được biến đổi, việc chụp cần được thực hiện bằng cách tham chiếu, nếu không bạn sẽ không thể sửa đổi nó. Nhưng điều này là không thể, bởi vì trong trường hợp đã đề cập trước đó, việc đóng cửa được trả về và được sử dụng ngoài phạm vi định nghĩa của nó, khả năng biến đổi cũng nằm ngoài phạm vi và có khả năng bị phân phối. Đây là lý do cho giới hạn ban đầu.

let mutableAddOne() = 
    let mutable x = 1 
    let f y = x <- x + y // x would be referenced, not copied 
    f 

let g = mutableAddOne() 
g 3 // x is now out of scope, so the reference is invalid! 
     // mutableAddOne doesn't compile, because if it did, then this would fail. 

Tuy nhiên, nếu biến đổi là toàn cục thì không có vấn đề phạm vi nào và trình biên dịch chấp nhận. Nó không chỉ là fsi; nếu bạn cố gắng để biên dịch chương trình sau đây với fsc, nó hoạt động:

module Working 

let mutable x = 1 // x is global, so it never goes out of scope 

let mutableAddOne() = 
    let f y = x <- x + y // referencing a global. No problem! 
    f 

let g = mutableAddOne() 
g 3 // works as expected! 

Tóm lại, như kwingho nói, nếu bạn muốn có một kết thúc cho phép chụp một giá trị có thể thay đổi địa phương, sử dụng một ref. Chúng được cấp phát đống (ngược lại với ngăn xếp cục bộ được phân bổ theo từng ngăn xếp), miễn là việc đóng cửa giữ một tham chiếu đến nó, nó sẽ không được giải phóng.

Các vấn đề liên quan