Các bản đồ được chuyển theo giá trị hay bằng tham chiếu trong Go?


90

Các bản đồ được chuyển theo giá trị hoặc tham chiếu trong Go?

Luôn có thể xác định một hàm như sau, nhưng đây có phải là một hàm quá mức cần thiết không?

func foo(dat *map[string]interface{}) {...}

Câu hỏi tương tự cho giá trị trả lại. Tôi nên trả lại một con trỏ cho bản đồ hay trả lại bản đồ dưới dạng giá trị?

Mục đích của tất nhiên là để tránh sao chép dữ liệu không cần thiết.


4
blog.golang.org/go-maps-in-action : Các loại bản đồ là các loại tham chiếu, như con trỏ hoặc lát cắt, và do đó giá trị của m ở trên là nil; nó không trỏ đến một bản đồ đã khởi tạo. Một bản đồ nil hoạt động giống như một bản đồ trống khi đọc, nhưng việc cố gắng ghi vào một bản đồ nil sẽ gây ra sự hoảng loạn trong thời gian chạy; đừng làm vậy. Để khởi tạo một bản đồ, sử dụng được xây dựng trong thực hiện chức năng
mh-cbon

2
Mọi thứ trong cờ vây đều được thông qua giá trị. Một số giá trị tình cờ là con trỏ hoặc cấu trúc chứa con trỏ. (bạn có thể muốn *maptrong một số trường hợp, nếu bạn cần chỉ định lại giá trị bản đồ tại một địa chỉ)
JimB

mh-cbon, không có loại tham chiếu nào trong cờ vây.
Inanc Gumus

@ mh-cbon Tôi không nói về kiểu tham chiếu. Tôi đang hỏi liệu một bản đồ có được chuyển qua tham chiếu hay không, tương đương với việc hỏi xem địa chỉ của bản đồ được truyền dưới dạng đối số hay "bản sao" của bản đồ (được truyền theo giá trị).
chmike

1
@ mh-cbon Chính xác, bản đồ là con trỏ tới hmap.
Inanc Gumus

Câu trả lời:


80

Trong chủ đề này, bạn sẽ tìm thấy câu trả lời của mình:

Golang: Truy cập bản đồ bằng cách sử dụng tham chiếu của nó

Bạn không cần sử dụng con trỏ với bản đồ.

Loại bản đồ là loại tham chiếu, như con trỏ hoặc lát cắt [1]

Nếu bạn cần thay đổi Phiên, bạn có thể sử dụng một con trỏ:

map[string]*Session

https://blog.golang.org/go-maps-in-action


15
Để tránh bất kỳ kẻ thù nào, hãy lưu ý rằng bản đồ chỉ được chuyển bằng tham chiếu sau khi được khởi tạo và khi được khởi tạo lại bên trong một hàm, tham chiếu ban đầu sẽ không được cập nhật. Đây là một ví dụ minh họa về sân chơi: play.golang.org/p/Q6vrAmmJWR6 Hoặc một bài viết đầy đủ của Dave Cheny dave.cheney.net/2017/04/29/there-is-no-pass-by-reference-in-go
Sindre Myren, 27/07/18

18

Dưới đây là một số phần trong Nếu bản đồ không phải là một biến tham chiếu, nó là gì? bởi Dave Cheney:

Giá trị bản đồ là một con trỏ tới một runtime.hmapcấu trúc.

và kết luận:

Phần kết luận

Bản đồ, giống như các kênh, nhưng không giống như các lát, chỉ là con trỏ đến các loại thời gian chạy. Như bạn đã thấy ở trên, bản đồ chỉ là một con trỏ đến một runtime.hmap cấu trúc.

Bản đồ có cùng ngữ nghĩa con trỏ như bất kỳ giá trị con trỏ nào khác trong chương trình Go. Không có gì kỳ diệu khi trình biên dịch viết lại cú pháp bản đồ thành các lệnh gọi đến các hàm trong runtime/hmap.go.

Và một chút thú vị về lịch sử / giải thích mapcú pháp:

Nếu bản đồ là con trỏ, phải không *map[key]value?

Một câu hỏi hay là nếu các bản đồ là giá trị con trỏ, tại sao biểu thức make(map[int]int)lại trả về một giá trị có kiểu map[int]int. Nó không nên trả lại a *map[int]int? Ian Taylor đã trả lời điều này gần đây trong một chủ đề golang-nut 1 .

Trong những ngày đầu tiên mà chúng ta gọi là bản đồ bây giờ được viết dưới dạng con trỏ, vì vậy bạn đã viết *map[int]int. Chúng tôi rời xa điều đó khi nhận ra rằng không ai viết mapmà không viết *map.

Có thể lập luận rằng đổi tên kiểu từ *map[int]intthành map[int]int, trong khi khó hiểu vì kiểu không giống như một con trỏ, ít gây nhầm lẫn hơn một giá trị hình con trỏ không thể được tham chiếu.


1

Không. Bản đồ là tham chiếu theo mặc định.

    package main

    import "fmt"

    func mapToAnotherFunction(m map[string]int) {
        m["hello"] = 3
        m["world"] = 4
        m["new_word"] = 5
    }

    // func mapToAnotherFunctionAsRef(m *map[string]int) {
    // m["hello"] = 30
    // m["world"] = 40
    // m["2ndFunction"] = 5
    // }

    func main() {
        m := make(map[string]int)
        m["hello"] = 1
        m["world"] = 2

        // Initial State
        for key, val := range m {
            fmt.Println(key, "=>", val)
        }

        fmt.Println("-----------------------")

        mapToAnotherFunction(m)
        // After Passing to the function as a pointer
        for key, val := range m {
            fmt.Println(key, "=>", val)
        }

        // Try Un Commenting This Line
        fmt.Println("-----------------------")

        // mapToAnotherFunctionAsRef(&m)
        // // After Passing to the function as a pointer
        // for key, val := range m {
        //  fmt.Println(key, "=>", val)
        // }

        // Outputs
        // hello => 1
        // world => 2
        // -----------------------
        // hello => 3
        // world => 4
        // new_word => 5
        // -----------------------

    }

Từ Golang Blog-

Loại bản đồ là loại tham chiếu, như con trỏ hoặc lát cắt, và vì vậy giá trị của m ở trên là 0; nó không trỏ đến một bản đồ đã khởi tạo. Một bản đồ nil hoạt động giống như một bản đồ trống khi đọc, nhưng việc cố gắng ghi vào một bản đồ nil sẽ gây ra sự hoảng loạn trong thời gian chạy; đừng làm vậy. Để khởi tạo bản đồ, hãy sử dụng hàm tạo sẵn:

// Ex of make function
m = make(map[string]int)

Liên kết đoạn mã Chơi với nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.