2010-12-18 61 views
6

Bạn biết cảnh đó trong số Tạm biệt và cảm ơn tất cả các cá nơi mà Arthur rất vui mừng, anh dừng một người phục vụ và yêu cầu biết, "Tại sao thức ăn này lại ngon thế?" Tôi đang ở trong tình huống đó. Scala dường như đang làm chính xác những gì tôi muốn, nhưng tôi không hiểu nó làm như thế nào. Hãy xem xét những điều sau đây:Làm cách nào để sửa đổi danh sách Nil?

scala> var v = Nil:List[String]; 
v: List[String] = List() 

scala> v.length 
res38: Int = 0 

scala> v ::= "Hello" 

scala> v.length 
res39: Int = 1 

scala> Nil.length 
res40: Int = 0 

Đó chính xác là những gì bạn mong đợi, nhưng nó diễn ra như thế nào?

Nil là một đối tượng mở rộng Danh sách [Không có gì], là loại phụ của Danh sách [Chuỗi], do đó, bài tập hoạt động tốt, nhưng đó là danh sách không thể thay đổi, phải không? Vì vậy, tôi không nên để có thể gắn thêm vào nó. Nhưng tôi có thể gắn thêm vào nó, hoặc ít nhất tôi có thể nối thêm vào v, mà tôi đã nghĩ đến Nil. v được thay đổi, nhưng Nil thì không.

Vì vậy, WTF? Liệu Scala có một số ngữ nghĩa sao chép sửa đổi thông minh mà tôi không biết? Nil có thực sự là một hàm trả về các danh sách trống không? Hơn nữa, có cách nào tôi có thể làm cho REPL trả lời những câu hỏi này không?

Trả lời

16

Khi Scala thấy

v ::= "Hello" 

nó kiểm tra đầu tiên nếu v biết phương pháp ::=. Trong trường hợp này (loại List), nó không, vì vậy, vì phương pháp này bao gồm duy nhất của các biểu tượng và kết thúc với một = dấu, nó cố gắng cái gì khác:

v = v.::("Hello") 

đó, tình cờ, được viết "Hello" :: v trong ký hiệu infix. Bây giờ, kể từ v biết phương thức ::, hoạt động và trả về List mới, sau đó được gán cho v như được chỉ định.

Nhân tiện, nó đang được thêm vào, không phụ thêm.

4

Khi bạn sử dụng từ khóa var, bạn không "dịch sang số final" theo nghĩa Java. Thay vào đó, var cho phép chuyển nhượng lại. Khi bạn gọi cho toán tử ::=, bạn thực sự chỉ định lại những gì v trỏ đến. Toán tử ::= trả về một danh sách mới mới, không phải danh sách gốc có "Hello" được thêm vào danh sách đó. Do đó, v hiện trỏ đến "Xin chào" chứ không phải danh sách Nil.

Ở đây, xem này:

var myThing = new List(1, 2, 3) 
var myOhterThing = myThing 

myThing = new List(1, 2, 3, 4) 

Nó gần giống như nói "lấy danh sách đầu tiên, sao chép nó và thêm một '4' vào nó ngay gán 'myThing' để trỏ đến danh sách đó.. " Sử dụng toán tử đó bạn đã thực hiện hiệu quả điều tương tự. Viết nó ra theo cách này cho phép bạn thấy điều đó.

2

Không thay đổi được. Khi bạn chống lại nó (:) bạn sẽ có được một thể hiện mới cũng không thay đổi.

Hãy thử điều này:

val v1 = Nil 
val v2 = "Hello" :: v1 
v1 == v2 

(bạn sẽ nhận sai vì họ không trỏ đến cùng một đối tượng)

Với v là một var bạn có thể gán giá trị cho nó.

Vì vậy, khi bạn có:

v ::= "Hello" // what you really have is: 
v = "Hello" :: v // or 
v = "Hello" :: Nil // or 
v = List("Hello") 

Trên đây tạo ra một danh sách mới và Nil còn lại không thay đổi. Nó tương tự như bổ sung String trong Java. Vì String là bất biến, bạn không bao giờ thay đổi một cá thể đơn lẻ - chỉ tạo một cá thể mới.

Vì Nil không thay đổi, Nil.length = 0.

3

Hãy thử với giá trị v, để xem điều gì có thể thay đổi. :)

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