dongzhu3548
dongzhu3548
2018-10-06 17:50

切片和贴图之间的行为差​​异

  • IT行业问题
  • 计算机技术
  • it技术
  • 编程语言问答
  • 互联网问答
已采纳

A related questions is here https://stackoverflow.com/a/12965872/6421681.

In go, you can do:

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

However,the following doesn't work:

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

An error is thrown:

panic: assignment to entry in nil map

Instead, you must:

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

I can't find the documentation for this behavior. I have read through all of effective go, and there's no mention of it there either.
I know that named return values are defined (i.e. memory is allocated; close to what new does) but not initialized (so make behavior isn't replicated).
After some experimenting, I believe this behavior can be reduced into understanding the behavior of the following code:

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

The issue seems that append likely calls make and allocates a new slice detecting that the capacity of s is 0. However, map never gets an explicit initialization.
The reason for this SO question is two-pronged. First, I would like to document the behavior on SO. Second, why would the language allow non-initializing definitions of slice and map? With my experience with go so far, it seems to be a pragmatic language (i.e. unused variables lead to compilation failure, gofmt forces proper formatting), so it would make sense for it to prevent the code from compiling.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

2条回答

  • dongtiaobeng7901 dongtiaobeng7901 3年前

    Try to assign in nil slice by index - you will get "panic: runtime error: index out of range" (example: https://play.golang.org/p/-XHh1jNyn5g)

    The only reason why append function works with nil, is that append function can do reallocation for the given slice. For example, if you trying to to append 6th element to slice of 5 elements with current capacity 5, it will create the new array with new capacity, copy all the info from old one, and swap the data array pointers in the given slice. In my understanding, it is just golang implementation of dynamic arrays.

    So, the nil slice is just a special case of slice with not enough capacity, so it would be reallocated on any append operation.

    More details on https://blog.golang.org/go-slices-usage-and-internals

    点赞 评论 复制链接分享
  • doumu9799 doumu9799 3年前

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

    A nil map behaves like an empty map when reading, but attempts to write to a nil map will cause a runtime panic; don't do that. To initialize a map, use the built in make function

    It seems like a nil map is considered a valid empty map and that's the reason they don't allocate memory for it automatically.

    点赞 评论 复制链接分享

为你推荐