Оголосити скибочку або зробити скибочку?


99

У чому полягає різниця між var s []intі s := make([]int, 0)?

Я вважаю, що обидва працюють, але хто з них кращий?


Перший створює nilфрагмент, тоді як другий створює emptyфрагмент (це термінологія, що використовується в книзі "Перехід до дії" ). Для того, щоб уникнути розміщення і той же відповідь тут, ви можете перевірити stackoverflow.com/a/45997533/1561148
tgogos

Відповіді:


95

У доповненні до fabriziom «s відповіді , ви можете побачити більше прикладів на" Go скибочками: використання і внутрішні органи ", де використання для []intзгадуються:

Оскільки нульове значення фрагмента ( nil) діє як зріз нульової довжини , ви можете оголосити змінну фрагмента, а потім додати його до циклу:

// 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
}

Це означає, що для додавання фрагмента вам не потрібно виділяти пам'ять спочатку: nilфрагмента p int[]достатньо, як фрагмент для додавання.


Чому ви думаєте, що це зробить розподіл? Ковпак дорівнює нулю, тому нічого не виділяється з маркою або без неї.
Арман Ордохані

1
@ArmanOrdookhani Погодився. Я просто вважаю декларацію var p []intпростішою, ніж використовувати make(яку я більше асоціюю з виділенням, хоча з обмеженням 0, воно нічого не виділяє). Що стосується читабельності, я вважаю за краще не використовувати makeтут.
VonC

1
Я більше орієнтуюся на використання літералів скрізь (наприклад p := []int{}). Оскільки ми зазвичай використовуємо :=синтаксис для декларування більшості змінних, більш природним є його скрізь, а не для виключень. Окрім цього, намагаючись продумати виділення, зазвичай підштовхують людей до передчасних оптимізацій.
Арман Ордуохані

113

Просте оголошення

var s []int

не виділяє пам'ять і sвказує на nilчас

s := make([]int, 0)

виділяє пам'ять і sвказує на пам'ять на фрагмент з 0 елементами.

Зазвичай перший є ідіоматичним, якщо ви не знаєте точного розміру вашої справи використання.


Чи можу я сказати те саме для карти? var m map [string] int vs m: = make (map [string] int)? Дякую.
Джошуа

11
Ні, вам потрібно зробити makeкарти, тому що навіть порожній mapпотребує місця, виділеного для якоїсь бухгалтерії.
twotwotwo

11
Якщо вам потрібно повернути фрагмент із 0 елементами (замість 'nil'), виконайте правильне використання.
Джесс

6
Якщо ви будуєте API і повертаєте масив як відповідь, за допомогою декларативної форми повернеться nilу випадку, якщо у вашому фрагменті немає елемента, а не порожній масив. Однак, якщо makeвикористовується для створення фрагмента, замість нього повернеться порожній масив, що, як правило, є бажаним ефектом.
robinmitra

6
Як згадується в коментарі до цієї відповіді: stackoverflow.com/a/29164565/1311538 , існують відмінності при спробі зробити такі дії, як json marshaling. Маршалінг нульового зрізу ( var s []int) призведе до отримання null, тоді як марширування порожнього зрізу ( s := make([]int, 0)) призведе до очікуваного[]
asgaines

8

Просто знайшов різницю. Якщо ви використовуєте

var list []MyObjects

а потім ви кодуєте вихід як JSON, ви отримуєте null.

list := make([]MyObjects, 0)

результати, []як очікувалося.


Так, останній досить корисний, коли ми хочемо відповісти масивом [] замість null
Nhan Tran

4

Трохи повніше (ще один аргумент у make) прикладі:

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

Вийшов:

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

Або з динамічним типом slice:

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

Вийшов:

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

2
Гарні приклади. +1
VonC
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.