Go中的地图初始化 [英] Map initialization in Go

查看:98
本文介绍了Go中的地图初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我了解,Go中的 slice map 类型非常相似。它们都是引用(或容器)类型。就抽象数据类型而言,它们分别表示一个数组和一个关联数组。

As far as I understand, types slice and map are similar in many ways in Go. They both reference (or container) types. In terms of abstract data types, they represent an array and an associative array, respectively.

但是,它们的行为却大不相同。

However, their behaviour is quite different.

var s []int
var m map[int]int

可以立即使用声明的切片(追加新项目或重新切片),我们不能对新声明的地图执行任何操作。我们必须调用 make 函数并显式初始化地图。因此,如果某个结构包含一个映射,则我们必须为该结构编写一个构造函数。

While we can use a declared slice immediately (append new items or reslice it), we cannot do anything with a newly declared map. We have to call make function and initialize a map explicitly. Therefore, if some struct contains a map we have to write a constructor function for the struct.

因此,问题是为什么无法添加一些合成糖并且既分配又初始化

So, the question is why it is not possible to add some syntaсtic sugar and both allocate and initialize the memory when declaring a map.

我确实在Google上搜索了这个问题,学会了一个新词 avtovivification,但仍然看不到原因。

I did google the question, learnt a new word "avtovivification", but still failing to see the reason.

我不是在谈论结构文字。是的,您可以通过提供诸如 m:= map [int] int {1:1} 之类的值来显式初始化地图。但是,如果您有某些结构

I am not talking about struct literal. Yes, you can explicitly initialize a map by providing values such as m := map[int]int{1: 1}. However, if you have some struct:

package main

import (
    "fmt"
)

type SomeStruct struct {
    someField map[int]int
    someField2 []int
}

func main() {
    s := SomeStruct{}
    s.someField2 = append(s.someField2, -1) // OK
    s.someField[0] = -1 // panic: assignment to entry in nil map
    fmt.Println(s)
}

不可能立即使用结构(所有字段均具有默认值)。必须为 SomeStruct 创建一个构造函数,该函数必须显式初始化地图。

It is not possible to use a struct immediately (with default values for all fields). One has to create a constructor function for SomeStruct which has to initialize a map explicitly.

推荐答案


尽管我们可以立即使用声明的切片(追加新项目或重新切片),但是我们不能对新声明的映射执行任何操作。我们必须调用 make 函数并显式初始化地图。因此,如果某些结构包含一个映射,我们必须为该结构编写一个构造函数。

While we can use a declared slice immediately (append new items or reslice it), we cannot do anything with a newly declared map. We have to call make function and initialize a map explicitly. Therefore, if some struct contains a map we have to write a constructor function for the struct.

那是不对的。切片和地图的默认值(或更准确地说,零值)均为。您可以对 nil 贴图进行相同操作,就像对 nil 切片一样。您可以检查 nil 映射的长度,也可以索引 nil 映射的索引(结果将为地图的值类型),例如以下所有方法都可以正常工作:

That's not true. Default value–or more precisely zero value–for both slices and maps is nil. You may do the "same" with a nil map as you can do with a nil slice. You can check length of a nil map, you can index a nil map (result will be the zero value of the value type of the map), e.g. the following are all working:

var m map[int]int

fmt.Println(m == nil) // Prints true
fmt.Println(len(m))   // Prints 0
fmt.Println(m[2])     // Prints 0

进入游乐场

您对零值切片的感觉更多是可以在其中添加值。的确如此,但是在幕后,将使用精确的 make分配新的切片() 内置函数,您必须调用该函数才能向其中添加条目,并且必须(重新)分配返回的切片。因此,零值切片比零值映射不再准备使用。 append() 只是负责必要的(重新)分配和复制。我们可以有一个等价的 addEntry()函数,您可以向其中传递一个映射值和键值对,如果传递的映射是 nil ,它可以分配一个新的地图值并返回它。如果您不调用 append(),则无法像您一样将值添加到 nil 切片中无法将条目添加到 nil 映射中。

What you "feel" more about the zero-value slice is that you may add values to it. This is true, but under the hood a new slice will be allocated using the exact make() builtin function that you'd have to call for a map in order to add entries to it, and you have to (re)assign the returned slice. So a zero-value slice is "no more ready for use" than a zero-value map. append() just takes care of necessary (re)allocation and copying over. We could have an "equivalent" addEntry() function to which you could pass a map value and the key-value pairs, and if the passed map is nil, it could allocate a new map value and return it. If you don't call append(), you can't add values to a nil slice, just as you can't add entries to a nil map.

切片和映射的零值为 nil (而不是初始化的切片或映射)是性能和效率。映射或切片值(变量或结构字段)通常永远不会被使用或不会立即使用,因此,如果将它们在声明时分配,那将浪费内存(和某些CPU)资源,更不用说它为垃圾收集器增加了工作量。同样,如果零值将是一个初始化值,则它通常会不够用(例如,0大小的切片无法容纳任何元素),并且在向其添加新元素时,它通常会被丢弃(因此,初始分配将是完全浪费)。

The primary reason that the zero value for slices and maps is nil (and not an initialized slice or map) is performance and efficiency. It is very often that a map or slice value (either variable or a struct field) will never get used, or not right away, and so if they would be allocated at declaration, that would be a waste of memory (and some CPU) resources, not to mention it gives more job to the garbage collector. Also if the zero value would be an initialized value, it would often be insufficient (e.g. a 0-size slice cannot hold any elements), and often it would be discarded as you add new elements to it (so the initial allocation would be a complete waste).

是的,有些情况下您确实想立即使用切片和地图,在这种情况下,您可以调用 make( )或使用复合文字。您还可以使用 make()的特殊形式,在其中为地图提供(初始)容量,从而避免将来对地图内部结构进行重组(通常需要进行不可忽略的计算) )。自动的非 nil 默认值无法猜测您需要的容量。

Yes, there are cases when you do want to use slices and maps right away, in which cases you may call make() yourself, or use a composite literal. You may also use the special form of make() where you supply the (initial) capacity for maps, avoiding future restructuring of the map internals (which usually requires non-negligible computation). An automatic non-nil default value could not guess what capacity you'd require.

这篇关于Go中的地图初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆