Разница в поведении между срезами и картами - PullRequest
0 голосов
/ 06 октября 2018

Соответствующие вопросы здесь https://stackoverflow.com/a/12965872/6421681.

На ходу вы можете сделать:

func numsInFactorial(n int) (nums []int) {
    // `nums := make([]int)` is not needed
    for i := 1; i <= n; i++ {
        nums = append(nums, i)
    }
    return
}

Однако следующее не работает:

func mapWithOneKeyAndValue(k int, v int) (m map[int]int) {
    m[k] = v
    return
}

Выдается ошибка:

panic: assignment to entry in nil map

Вместо этого вы должны:

func mapWithOneKeyAndValue(k int, v int) map[int]int {
    m := make(map[int]int)
    m[k] = v
    return
}

Я не могу найти документацию для этого поведения.Я прочитал все эффективные ходы, и там тоже нет упоминаний об этом.
Я знаю, что именованные возвращаемые значения определены (т. Е. Выделена память; близко к тому, что делает new), но не инициализированы (поэтому поведение make не реплицируется).
После некоторых экспериментов, я считаю, что это поведение может быть сведено к пониманию поведения следующего кода:

func main() {
    var s []int // len and cap are both 0
    var m map[int]int

    fmt.Println(s) // works... prints an empty slice
    fmt.Println(m) // works... prints an empty map

    s = append(s, 10) // returns a new slice, so underlying array gets allocated
    fmt.Println(s) // works... prints [10]

    m[10] = 10 // program crashes, with "assignment to entry in nil map"
    fmt.Println(m)
}

Кажется, что проблема append вызывает make и выделяет обнаружение нового срезачто емкость s составляет 0.Однако map никогда не получает явную инициализацию.
Причина этого СО вопроса состоит из двух частей.Во-первых, я хотел бы документировать поведение на SO.Во-вторых, почему язык допускает неинициализирующие определения slice и map?С моим опытом работы с этим языком кажется прагматичным (т. Е. Неиспользуемые переменные приводят к сбою компиляции, gofmt вызывает правильное форматирование), поэтому имеет смысл предотвратить компиляцию кода.

Ответы [ 2 ]

0 голосов
/ 06 октября 2018

Попробуйте назначить nil-фрагмент по индексу - вы получите «панику: ошибка времени выполнения: индекс выходит за пределы диапазона» (пример: https://play.golang.org/p/-XHh1jNyn5g)

Единственная причина, по которой функция добавления работает с nil, заключается в том, чтоФункция append может выполнить перераспределение для данного среза, например, если вы пытаетесь добавить 6-й элемент к срезу из 5 элементов с текущей емкостью 5, он создаст новый массив с новой емкостью, скопирует всю информацию из старого ипоменяйте местами указатели массива данных в данном слайсе. В моем понимании, это просто реализация динамических массивов golang.

Итак, нулевой слайс - это просто особый случай слайса с недостаточной емкостью, поэтому он будетперераспределяется при любой операции добавления.

Подробнее о https://blog.golang.org/go-slices-usage-and-internals

0 голосов
/ 06 октября 2018

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

Нулевая карта ведет себя как пустая карта при чтении, но попытки записи на нулевую карту вызовут панику во время выполнения;не делай этогоЧтобы инициализировать карту, используйте встроенную функцию make

Кажется, что nil-карта считается допустимой пустой картой, и именно поэтому они не выделяют для нее память автоматически.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...