Khai báo lát cắt hay tạo lát cắt?


98

Trong Golang, sự khác biệt giữa var s []ints := make([]int, 0)?

Tôi thấy rằng cả hai đều hoạt động, nhưng cái nào tốt hơn?


Cái đầu tiên tạo ra một nillát, trong khi cái thứ hai tạo ra một emptylát cắt (đây là thuật ngữ được sử dụng trong "Sách hành động" ). Để tránh đăng cùng một câu trả lời ở đây, bạn có thể kiểm tra stackoverflow.com/a/45997533/1561148
tgogos

Câu trả lời:


94

Ngoài câu trả lời của fabriziom , bạn có thể xem thêm các ví dụ khác tại " Go Slices: cách sử dụng và nội bộ ", trong đó đề cập đến việc sử dụng cho :[]int

Vì giá trị 0 của một lát cắt ( nil) hoạt động giống như một lát cắt có độ dài bằng 0 , bạn có thể khai báo một biến lát cắt và sau đó thêm vào nó trong một vòng lặp:

// Filter returns a new slice holding only
// the elements of s that satisfy f()
func Filter(s []int, fn func(int) bool) []int {
    var p []int // == nil
    for _, v := range s {
        if fn(v) {
            p = append(p, v)
        }
    }
    return p
}

Nó có nghĩa là, để thêm vào một lát, trước tiên bạn không phải cấp phát bộ nhớ: nillát cắt p int[]đủ như một lát để thêm vào.


Tại sao bạn nghĩ rằng nó sẽ thực hiện một phân bổ? Cap bằng 0 nên không có gì được phân bổ có hoặc không có make.
Arman Ordookhani

1
@ArmanOrdookhani Đồng ý. Tôi chỉ thấy khai báo var p []intdễ dàng hơn so với việc sử dụng make(mà tôi liên kết nhiều hơn với cấp phát, mặc dù với giới hạn 0, nó sẽ không phân bổ bất cứ thứ gì). Về khả năng đọc, tôi không thích sử dụng makeở đây.
VonC

Tôi hướng tới việc sử dụng các chữ ở khắp mọi nơi (ví dụ p := []int{}). Vì chúng ta thường sử dụng :=cú pháp để khai báo hầu hết các biến, nên sẽ tự nhiên hơn nếu có nó ở mọi nơi thay vì có một ngoại lệ cho các slice. Khác với điều này, việc cố gắng nghĩ đến việc phân bổ thường thúc đẩy mọi người tiến tới tối ưu hóa quá sớm.
Arman Ordookhani

113

Khai báo đơn giản

var s []int

không phân bổ bộ nhớ và strỏ đến nil, trong khi

s := make([]int, 0)

cấp phát bộ nhớ và strỏ tới bộ nhớ tới một lát cắt có 0 phần tử.

Thông thường, cái đầu tiên khó hiểu hơn nếu bạn không biết kích thước chính xác của trường hợp sử dụng của mình.


Tôi có thể nói như vậy đối với bản đồ? var m map [string] int vs m: = make (map [string] int)? Cảm ơn.
joshua

11
Không, bạn cần lập makebản đồ, bởi vì ngay cả một khoảng trống cũng mapcần được phân bổ cho một số công việc ghi sổ.
twotwotwo

11
Nếu bạn cần trả về một lát cắt có 0 phần tử (thay vì 'nil'), hãy sử dụng đúng.
Jess

6
Nếu bạn đang xây dựng một API và trả về một mảng dưới dạng phản hồi, thì việc sử dụng biểu mẫu khai báo sẽ trả về niltrong trường hợp lát cắt của bạn không có bất kỳ phần tử nào, thay vì một mảng trống. Tuy nhiên, nếu makeđược sử dụng để tạo lát cắt, một mảng trống sẽ được trả về thay thế, đây thường là hiệu ứng mong muốn.
robinmitra

6
Như đã đề cập trong nhận xét về câu trả lời này: stackoverflow.com/a/29164565/1311538 , có sự khác biệt khi cố gắng thực hiện những việc như json marshaling. Marshaling slice nil ( var s []int) sẽ sản xuất null, trong khi marshaling slice rỗng ( s := make([]int, 0)) sẽ sản xuất dự kiến[]
asgaines

8

Chỉ cần tìm thấy một sự khác biệt. Nếu bạn dùng

var list []MyObjects

và sau đó bạn mã hóa đầu ra dưới dạng JSON, bạn sẽ nhận được null.

list := make([]MyObjects, 0)

kết quả []như mong đợi.


yah, cái sau khá hữu ích khi chúng ta muốn phản hồi bằng mảng [] thay vì null
Nhan Tran

4

makeVí dụ hoàn toàn hơn một chút (thêm một đối số trong ):

slice := make([]int, 2, 5)
fmt.Printf("length:  %d - capacity %d - content:  %d", len(slice), cap(slice), slice)

Ngoài:

length:  2 - capacity 5 - content:  [0 0]

Hoặc với loại động của slice:

slice := make([]interface{}, 2, 5)
fmt.Printf("length:  %d - capacity %d - content:  %d", len(slice), cap(slice), slice)

Ngoài:

length:  2 - capacity 5 - content:  [<nil> <nil>]

2
Những ví dụ điển hình. +1
VonC
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.