2016-09-22 17 views
7

Tôi đã được giới thiệu dữ liệu đó, theo mặc định là không thay đổi trong F #. Khi chúng ta gán lại giá trị cho một biến nào đó, điều thực sự xảy ra là nó rebinds giá trị của biến, nhưng thiết lập một giá trị mới là điều khác nhau. Rebinding được gọi là Shadowing trong khi thiết lập giá trị mới là không thể nếu chúng ta rõ ràng không nói rằng giá trị của biến là mutable.Bóng tối so với giá trị cài đặt trong F #

Ai đó có thể giải thích cho tôi khái niệm này chi tiết không? Sự khác biệt giữa shadowing (rebinding) bởi

let var = "new_value" 

và Thiết lập giá trị mới là những gì như

var <- "new_value" 

Đây có phải là một khoảnh khắc, rằng trong rebinding chúng ta tạo ra một đối tượng khác và chúng ta gán địa chỉ của đối tượng đó để biến trong khi ở ví dụ thứ hai, chúng ta thay đổi giá trị của chính nó? Tôi mang điều đó từ sự hiểu biết heap/stack của bộ nhớ .. Tôi có thể sai.

Cảm ơn

Trả lời

9

Shadowing là khi bạn tạo một mới ràng buộc có sử dụng tên giống như một ràng buộc trước. Điều này "bóng" tên ban đầu, mà giấu nó nhưng không thay đổi hoặc thay thế nó. Hãy thử điều này trong FSI để xem:

let foo = 42 

let printFoo() = 
    printfn "%i" foo 

printFoo() ;; 

này sẽ in:

42 

val foo : int = 42 
val printFoo : unit -> unit 
val it : unit =() 

Sau đó thêm:

// ... more code 
let foo = 24 

printfn "%i" foo // prints 24 
printFoo();; 

này sẽ in:

24 
42 

val foo : int = 24 
val it : unit =() 

Lưu ý rằng nó vẫn in 42 khi bạn gọi printFoo() - Hàm nhìn thấy ràng buộc ban đầu (không bị mờ), nhưng bản in mới cho thấy giá trị mới.

Sử dụng <- để biến một giá trị có thể thay đổi đòi hỏi một ràng buộc:

let mutable bar = 42 

let printBar() = 
    printfn "%i" bar 

printBar();; 

này, giống như ở trên, bản in 42. Lưu ý rằng bạn ghi đè lên các hành vi bất biến mặc định ở đây với các từ khóa có thể thay đổi.

Sau đó bạn thay đổi giá trị trong phạm vi có thể thay đổi ràng buộc:

bar <- 24 
printfn "%i" bar 
printBar();; 

này sẽ in 24 hai lần, từ đó, không giống như các phiên bản shadowed, các đột biến làm thay đổi bản gốc ràng buộc. Nếu bạn để mutable tắt trong ràng buộc ban đầu, bạn sẽ gặp lỗi khi sử dụng <-.

2

Bất cứ khi nào tôi tự hỏi những gì thực sự đang xảy ra tôi sử dụng các công cụ như ILSpy

Ví dụ:

let f() = 
    let x = Dictionary<int, string>() 
    let mutable x = ResizeArray<int> 16 
    x <- ResizeArray<int> 16 

Sử dụng ILSpy để dịch ngược nó trong mã C# nó trở thành:

public static void f() 
{ 
    Dictionary<int, string> x = new Dictionary<int, string>(); 
    List<int> x2 = new List<int>(16); 
    x2 = new List<int>(16); 
} 

Ở đây nó là rõ ràng hơn sự khác biệt giữa shadowing và setting.

Làm mờ x tạo biến mới có tên x2.

Cài đặt là bài tập bình thường.

4

Để thêm vào câu trả lời tuyệt vời của Reed Copsey, nếu bạn đang viết một vòng lặp nơi bạn thay đổi giá trị của bộ tích lũy, bạn sẽ đặt giá trị ban đầu là mutable. Ví dụ, bạn có thể làm điều này.

let mutable acc = 0 // declaration 
for i in 1..100 do 
    acc <- acc + i // assignment 

này là nhiều hơn hoặc ít tương đương với mã C#:

var acc = 0; 
for (int i = 1; i <= 100; i++) 
{ 
    acc = acc + i; // assignment 
    // Another way to write this: 
    // acc += i; 
} 

Tuy nhiên, trong Shadowing, như trong F này # đoạn mã:

let acc = 0 // declaration 
for i in 1..100 do 
    let acc = acc + i // another declaration only within the loop 

Bạn đang không thực sự làm bất cứ điều gì hữu ích!! Khai báo thứ hai chỉ có phạm vi trong vòng lặp for và nó không thay đổi giá trị của acc gốc.

Một thô C# tương đương sẽ là:

var acc = 0; // declaration 
for (int i = 1; i <= 100; i++) 
{ 
    var acc2 = acc + i; // another declaration only within the loop 
} 

Lưu ý rằng việc sử dụng acc (thay vì acc2) cho biến bên trong sẽ không biên dịch trong C#, vì nó không có Shadowing trong bối cảnh này.

Việc sử dụng bóng tối là, nó ngăn không cho sử dụng biến thể gốc trong một khối mã mà bạn không muốn. Vì vậy, có một biến ít hơn để lo lắng.

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