1

I'm new to Go and try to understand the language in order to write efficient code. In the following code, sizes of the two arrays differ by 140%, can someone explain this?

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    ind1 := make([]bool, 10)
    var ind2 [10]bool
    fmt.Println(unsafe.Sizeof(ind1)) // 24
    fmt.Println(len(ind1)) // 10
    fmt.Println(unsafe.Sizeof(ind2)) // 10
    fmt.Println(len(ind2)) // 10
}

The size of the first array remains 10, even in case the capacity is set explicitly:

    ind1 := make([]bool, 10, 10)

Can someone explain this? Is there any additional overhead in using make? If yes, why is it recommended to use make over default initialization?

icza
  • 389,944
  • 63
  • 907
  • 827
Robin
  • 424
  • 4
  • 17
  • 1
    The first thing when learning Go is to work through the Tour of Go (https://tour.golang.org). The second thing is to do it again. The third thing is reading Effective Go (https://golang.org/doc/effective_go.html). The fourth thing is reading the Spec (https://golang.org/ref/spec). Then you redo the tour and then you worry about efficient code. Not earlier :-) – Volker Feb 13 '17 at 11:02

2 Answers2

5

Arrays and slices in Go are different things.

Your ind1 is a slice, and ind2 is an array. The length of an array is part of the type, so for example [2]bool and [3]bool are 2 different array types.

A slice in Go is a descriptor for a contiguous segment of an underlying array and provides access to a numbered sequence of elements from that array. This slice header is a struct-like data structure represented by the type reflect.SliceHeader:

type SliceHeader struct {
        Data uintptr
        Len  int
        Cap  int
}

It contains a data pointer (to the first element of the represented segment), a length and a capacity.

The unsafe.SizeOf() function returns the size in bytes of the hypothetical variable as if it would hold the passed value. It does not include any memory possibly referenced by it.

So if you pass a slice value (ind1), it will tell you the size of the above mentioned slice header. Note that the size of the fields of SliceHeader are architecture dependent, e.g. int may be 4 bytes on one platform and it may be 8 bytes on another. The size 24 applies to 64-bit architectures.

The Go Playground runs on a 32-bit architecture. Let's see this example:

fmt.Println(unsafe.Sizeof(make([]bool, 10)))
fmt.Println(unsafe.Sizeof(make([]bool, 20)))

fmt.Println(unsafe.Sizeof([10]bool{}))
fmt.Println(unsafe.Sizeof([20]bool{}))

Output (try it on the Go Playground):

12
12
10
20

As you can see, no matter the length of the slice you pass to unsafe.SizeOf(), it always returns 12 on the Go Playground (and 24 on 64-bit architectures).

On the other hand, an array value includes all its elements, and as such, its size depends on its length. Size of [10]bool is 10, and size of [20]bool is 20.

See related questions+answers to learn more about slices, arrays and the difference and relation between them:

How do I find the size of the array in go

Why have arrays in Go?

Why use arrays instead of slices?

Must read blog posts:

Go Slices: usage and internals

Arrays, slices (and strings): The mechanics of 'append'

Community
  • 1
  • 1
icza
  • 389,944
  • 63
  • 907
  • 827
1

ind1 is a slice (the type is []bool).

ind2 is an array (the type is [10]bool).

They are not of the same type.

The result of unsafe.Sizeof(ind1) probably has nothing to do with the arguments passed to make.

cshu
  • 5,654
  • 28
  • 44