dora12345678
2019-01-10 08:20
浏览 86
已采纳

Golang地图初始化

As far as I understand, types slice and map are similar in many ways in Golang. 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

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.

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

ADDED: 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)
}

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.

图片转代码服务由CSDN问答提供 功能建议

据我了解,键入 slice map 在Golang中有很多相似之处。 它们都是 reference (或 container )类型。 就抽象数据类型而言,它们分别表示一个数组和一个关联数组。

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

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

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

所以,问题是为什么在声明地图时为什么无法添加一些合成糖并且既分配又初始化内存。

I 谷歌做了这个问题,学会了一个新词“ avtovivification”,但仍然看不出原因。

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

 < 代码>包main 
 
import(
“ fmt” 
)
 
type SomeStruct struct {
 someField map [int] int 
 someField2 [] int 
} 
 
func main(){\  ns:= SomeStruct {} 
 s.someField2 = append(s.someField2,-1)// OK 
 s.someField [0] = -1 //恐慌:分配给nil map中的条目
 fmt.Println  (s)
} 
   
 
 

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

  • 写回答
  • 好问题 提建议
  • 追加酬金
  • 关注问题
  • 邀请回答

2条回答 默认 最新

  • dongtan6543 2019-01-10 08:59
    最佳回答

    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.

    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
    

    Try it on the Go Playground.

    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.

    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).

    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.

    评论
    解决 无用
    打赏 举报
查看更多回答(1条)