2013-08-06 77 views
5

Hãy nói rằng tôi có một cấu trúc đơn giản một với một tài sản chuỗi b:Bản đồ của cấu trúc vs mảng của cấu trúc trong Go

type A struct { 
    B string 
} 

Các mã sau đây sử dụng một mảng của A loại:

testArray := []A{A{}} 
testArray[0].B = "test1" 
fmt.Println(testArray[0].B) 

Sẽ in ra "test1" như mong đợi.

Nhưng mã này mà dường như đều rất đơn giản:

testMap := make(map[string]A) 
testMap["key"] = A{} 
testMap["key"].B = "test2" 
fmt.Println(testMap["key"].B) 

Sẽ không in ra "test2" mà thay vào đó sẽ dẫn đến các lỗi sau:

cannot assign to testMap["key"].B

Vì vậy, tại sao gán cho subproperty trong một kết quả bản đồ trong một lỗi trong khi gán cho subproperty trong một mảng làm việc như mong đợi? Tôi muốn biết cả hai lý do tại sao điều này không làm việc cho bản đồ VÀ tại sao nó hoạt động đối với mảng. Tôi cũng thích một số suy đoán về lý do tại sao họ thiết kế ngôn ngữ với sự khác biệt này giữa hai cấu trúc dữ liệu.

+0

'testArray' không phải là" mảng ". Nó là một "lát". "Array" là một cái gì đó khác nhau. – newacct

Trả lời

10

Tôi đã trả lời ở độ dài nào đó trong danh sách gửi thư, nhưng giải thích ngắn gọn là điều này không có tác dụng vì các mục nhập bản đồ không phải là địa chỉ. Điều đó có nghĩa là bạn không thể lấy địa chỉ của một mục nhập trong bản đồ. Và đó là vì việc thêm một giá trị mới vào bản đồ có thể khiến các mục bản đồ chuyển dịch xung quanh, để các địa chỉ thay đổi. Vì bạn không thể lấy địa chỉ của một mục nhập trong bản đồ, tất cả các hoạt động trên bản đồ sử dụng toàn bộ giá trị: sao chép toàn bộ giá trị ra khỏi bản đồ, thêm toàn bộ bản đồ vào bản đồ. Việc gán cho một trường của một cấu trúc trong một bản đồ sẽ yêu cầu một hoạt động đọc-sửa-ghi, các bản đồ không hỗ trợ (chúng có thể, nhưng chúng không, và có một chi phí để hỗ trợ chúng).

Các phần tử trong mảng và lát là địa chỉ vì chúng không di chuyển xung quanh sau khi chúng được tạo.

+1

Điều này đã trả lời câu hỏi của tôi. Nó không phải "chỉ vì đó là cách nó được thiết kế" hoặc "ma thuật" hay cái gì đó, lý do tại sao các mảng cho phép điều này và bản đồ không có ý nghĩa. Cảm ơn bạn! – GreenMachine

+0

Ngoài ra, bạn có câu trả lời chuyên sâu thậm chí còn hữu ích hơn. Nó có thể đáng để đăng tất cả ở đây nhưng bây giờ, đây là một liên kết đến nó: https://groups.google.com/d/msg/golang-nuts/FCcLsuWsF_U/qk6SLNcHvJIJ – GreenMachine

2

Phần tử mảng là lvalue. Với các bản đồ phức tạp hơn một chút. Trong:

m := map[T]U{} 
m[T(expr)] = U(expr) 

LHS m[T(expr)] một giá trị trái. Tuy nhiên, trong:

type U struct{ 
     F V 
} 

m := map[T]U{} 
m[T(expr)].F = 34 

LHS m[T(expr)].F không còn là giá trị nữa. Phần đầu tiên, m[T(expr)] đánh giá một phiên bản loại U. Ví dụ đó là "nổi", nó không còn nhà nữa. Gán cái gì đó cho các trường của nó chắc chắn là một sai lầm, do đó trình biên dịch hét lên.

Đó là nhiều hay ít cũng giống như sự khác biệt giữa:

var v U 
v.F = 42 // ok 
U{}.F = 42 // not ok 

Lên trên giải quyết vấn đề, bạn có thể sử dụng con trỏ đến một cấu trúc:

m := map[T]*U{} 
m[T(expr)].F = 42 

Bản đồ đầu tiên mang lại một con trỏ đến U sau đó được sử dụng để đặt trường.

1

Về mặt kỹ thuật, theo tham chiếu ngôn ngữ, biểu thức testmap["key"].B không phải là addressable, do đó, nó không thể được sử dụng như bên tay trái của assignment.

Vì vậy, câu hỏi có thể cần phải được chuyển sang: tại sao cụm từ đó không thể xử lý được? Tôi chưa hoàn toàn chắc chắn về điều đó ...

... ah. Đó là vì testmap["key"] đang cung cấp cho chúng tôi một bản sao của cấu trúc. Việc đột biến bản sao đó có lẽ không phải là những gì chúng tôi muốn làm, vì nó sẽ không ảnh hưởng đến cấu trúc ban đầu trong bản đồ.

4

Vấn đề là trong ví dụ trên bản đồ, testMap["key"] trả về một chữ, không phải con trỏ. Điều này có nghĩa là sửa đổi nó là vô nghĩa, do đó trình biên dịch không cho phép nó.Về cơ bản nó tương đương với:

v := testMap["key"] 
v.B = "test2" 

... và sau đó không bao giờ sử dụng v một lần nữa. Nó không có hiệu lực. Nó tương đương với việc không bao giờ thực hiện hai dòng đó ngay từ đầu. Đó là lý do tại sao trình biên dịch sẽ không cho phép bạn làm điều đó. Mặt khác, bạn đã làm cho nó thành một bản đồ của con trỏ đến A, bạn sẽ kinh doanh. này sẽ biên dịch:

testMap := make(map[string]*A) 
testMap["key"] = &A{} 
testMap["key"].B = "test2" 

Lý do mà các công trình này là dereferencing và gán một giá trị con trỏ không có ảnh hưởng.

+0

Tôi thích lời giải thích đó cho bản đồ, nhưng điều gì khác biệt về mảng? Mảng cũng không trả về con trỏ, vậy tại sao nó hoạt động trong ví dụ mảng? – GreenMachine

+0

... ma thuật, tôi nghĩ vậy. – joshlf

+0

Tôi nghĩ đó chỉ là cách ngôn ngữ được thiết kế. Mảng là ma thuật. Họ có thể làm điều đó về mặt lý thuyết với bản đồ, nhưng họ không vì lý do nào đó, tôi cho là vậy. – joshlf

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