Правильний спосіб ініціалізації порожнього фрагмента


227

Для оголошення порожнього фрагмента з нефіксованим розміром краще зробити:

mySlice1 := make([]int, 0)

або:

mySlice2 := []int{}

Просто цікаво, який з них є правильним.


2
Ви кажете "нефіксований розмір", але часточки ніколи не мають фіксованого розміру. Якщо ви не маєте на увазі нульову ємність. Зверніть увагу, якщо у вас є ідея / здогадка / підказка, яка ємність вам може знадобитися, тоді добре використовувати три версії аргументу. Наприклад, щоб скласти фрагмент ключів карти:keys := make([]int, 0, len(m)); for k, v := range m { keys := append(keys,k) }
Дейв C

1
Можливий дублікат Declare Slice або Make Slice?
користувач

Відповіді:


272

Дві альтернативи, які ви подали, є семантично однаковими, але їх використання make([]int, 0)призведе до внутрішнього виклику runtime.makeslice (Перейти 1.14).

Ви також можете залишити його зі nilзначенням:

var myslice []int

Як написано в блозі Golang.org :

нульовий зріз функціонально еквівалентний зрізу нульової довжини, хоча він не вказує ні на що. Він має нульову довжину і до нього можна додавати виділення.

Однак nilшматочок потрапить json.Marshal()у "null"той час, коли порожній шматочок буде маршалити"[]" , як вказував @farwayer.

Жоден з перерахованих вище варіантів не призведе до виділення, як вказував @ArmanOrdookhani.


4
Також згадайте на wiki github.com/golang/go/wiki/…
Grzegorz Żur

106
Будьте догляд: json.Marshal()повернуться nullдо var myslice []intі []для ініціалізувала зрізуmyslice := []int{}
farwayer

10
Також будьте обережні: reflect.DeepEqualрозрізняє нульовими часточки і не-нульовими скибочок: a := []int{}, var b []int,reflect.DeepEqual(a, b) // returns false
asgaines

1
Чому ви думаєте, що це зробить розподіл? Ковпачок дорівнює нулю, тому нічого не виділяється. Усі вказівники на речі з нульовою довжиною вказують на одне місце в пам’яті: play.golang.org/p/MPOKKl_sYvw
Arman Ordookhani

1
@ArmanOrdookhani Ви маєте рацію. Я спробував це, і також з'ясував, що я помилявся з моїм припущенням щодо однакових інструкцій зі складання. Виправлено!
Анісус

65

Вони рівноцінні. Дивіться цей код:

mySlice1 := make([]int, 0)
mySlice2 := []int{}
fmt.Println("mySlice1", cap(mySlice1))
fmt.Println("mySlice2", cap(mySlice2))

Вихід:

mySlice1 0
mySlice2 0

Обидва скибочки мають 0ємність, що означає, що обидва скибочки є0 довжину (не може бути більшою, ніж ємність), що означає, що обидва скибочки не мають елементів. Це означає, що 2 скибочки в кожному аспекті однакові.

Дивіться подібні запитання:

Який сенс мати нульовий шматочок та порожній шматочок у голангу?

nil slices vs non-nil фрагменти vs порожні фрагменти на мові Go


46

Як додаток до відповіді @ANisus ...

нижче наводиться деяка інформація з книги "Іди в дії" , яку, на мою думку, варто згадати:

Різниця між nil& emptyскибочками

Якщо ми думаємо про такий фрагмент:

[pointer] [length] [capacity]

тоді:

nil slice:   [nil][0][0]
empty slice: [addr][0][0] // points to an address

нульовий шматочок

Вони корисні, коли ви хочете представити фрагмент, який не існує, наприклад, коли у функції, яка повертає фрагмент, відбувається виняток.

// Create a nil slice of integers.
var slice []int

порожній шматочок

Порожні фрагменти корисні, коли ви хочете представляти порожню колекцію, наприклад, коли запит бази даних повертає нульові результати.

// Use make to create an empty slice of integers.
slice := make([]int, 0)

// Use a slice literal to create an empty slice of integers.
slice := []int{}

Незалежно від того, чи використовуєте ви нульовий скибочку або порожній шматок, вбудовані в функції append, lenі capпрацювати так само.


Перейдіть на приклад ігрового майданчика :

package main

import (
    "fmt"
)

func main() {

    var nil_slice []int
    var empty_slice = []int{}

    fmt.Println(nil_slice == nil, len(nil_slice), cap(nil_slice))
    fmt.Println(empty_slice == nil, len(empty_slice), cap(empty_slice))

}

відбитки:

true 0 0
false 0 0

Чи можемо ми отримати адресу порожнього фрагмента за один крок за допомогою make?
Simin Jie

Якщо ми подивимось на підпис функції , makeсхоже, не повертає адресу. Я вважаю, ви не можете зробити це за один крок.
tgogos

13

Порожній зріз і нульовий фрагмент ініціалізуються по-різному:

var nilSlice []int 
emptySlice1 := make([]int, 0)
emptySlice2 := []int{}

fmt.Println(nilSlice == nil)    // true
fmt.Println(emptySlice1 == nil) // false
fmt.Println(emptySlice2 == nil) // false

Що стосується всіх трьох скибочок, то лен і кришка - 0.


make([]int, 0)найкраще, тому що Jetbrains GoLand не скаржиться на те, що він "непотрібний", як це робиться у випадку []int{}. Це корисно при написанні одиничних тестів.
Анджей Реманн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.