0
votes

I will like to understand why when I copy a struct value into an interface it behaves like it does. In this code can someone help me understand why when I copy the value from mySlice into foo3 it behaves different than the other copies?

package main

import (
    "fmt"
    "unsafe"
)

type SliceOfInt []int

// when passing a slice to a method you are passing this data. Lets prove it
type SliceHeader struct {
    Data uintptr
    Len  int
    Cap  int
}

// Print the header of a slice. Its Data. Len and Cap
func GetHeaderOfSliceOfInt(s unsafe.Pointer) *SliceHeader {
    // this header needs to point to &mySlice but compiler will not let us. we have to use unsafe pointers
    var header *SliceHeader
    pointerToMySlice := s
    header = ((*SliceHeader)(pointerToMySlice))
    return header
}

func main() {

    // On go everything is passed by coping values. When you pass a slice to a function you are passing this:
    // reference: https://stackoverflow.com/a/39993797/637142
    /*
        type SliceHeader struct {
            Data uintptr
            Len  int
            Cap  int
        }
    */

    // create a new slice
    var mySlice SliceOfInt = make([]int, 0)
    mySlice = append(mySlice, 123456789) // append this number to mySlice

    // now we have a slice with len:1 and capacity:1. Lets prove it

    header := GetHeaderOfSliceOfInt(unsafe.Pointer(&mySlice))
    fmt.Println(*header)
    // this prints: {824635465728 1 1}
    // this means that on memory address 824635465728 there is an array with cap:1 and len:1

    // copy that header to someOtherSlice
    someOtherSlice := mySlice
    header = GetHeaderOfSliceOfInt(unsafe.Pointer(&someOtherSlice))
    fmt.Println(*header)
    // prints the same value {824635465728 1 1}

    // anyways if I go to address 824635465728 on my computer I shoul dbe able to find integer 123456789
    pointerToInteger := unsafe.Pointer((*header).Data)
    var integerVal *int = ((*int)(pointerToInteger))
    fmt.Println(*integerVal)

    // if I copy like this, it will print the correct header {824635465728 1 1}
    foo1 := mySlice
    fmt.Println(*GetHeaderOfSliceOfInt(unsafe.Pointer(&foo1)))

    // copy like this will also print the correct header {824635465728 1 1}
    foo2 := foo1
    fmt.Println(*GetHeaderOfSliceOfInt(unsafe.Pointer(&foo2)))

    // If I copy like this it will print the incorrect header. Why?
    var foo3 interface{} = mySlice
    fmt.Println(*GetHeaderOfSliceOfInt(unsafe.Pointer(&foo3)))

    // this last line prints {4746976 824635330392 0}
}

The output of the program is:

{824635465728 1 1}
{824635465728 1 1}
123456789
{824635465728 1 1}
{824635465728 1 1}
{4746976 824635330392 0}

Edit


I know that on I change foo to and cast it to `foo3.(SliceOfInt)` it will work. But why is that?