Official ref: https://go.dev/ref/spec#Types
basic datatypes are Value Types: e.g. int
boolean
string
array
struct
...
reference datatypes are:
- Slice
- Map
- Channel
- Pointer
- Interface
Slice
https://github.com/golang/go/blob/master/src/runtime/slice.go
type slice struct {
array unsafe.Pointer
len int
cap int
}
+------------+------------+------------+
| Pointer | Length | Capacity |
+------------+------------+------------+
| | |
V V V
[underneath array] ---> [1, 2, 3]
When dynamic expansion:
Basically, it allocates another space from memory and copies all the existing data from the old slice to the new slice, so the pointer of slice should change as well
package main
import "fmt"
func main() {
slice := []int{1, 2, 3}
fmt.Println("Init:")
fmt.Printf("slice: %v, len: %d, cap: %d, address: %p\n", slice, len(slice), cap(slice), &slice[0])
slice[0] = 2
fmt.Println("\nAfter modify:")
fmt.Printf("slice: %v, len: %d, cap: %d, address: %p\n", slice, len(slice), cap(slice), &slice[0])
slice = append(slice, 4)
fmt.Println("\nAfter append:")
fmt.Printf("slice: %v, len: %d, cap: %d, address: %p\n", slice, len(slice), cap(slice), &slice[0])
}
output:
Init:
slice: [1 2 3], len: 3, cap: 3, address: 0x14000016138
After modify:
slice: [2 2 3], len: 3, cap: 3, address: 0x14000016138
After append:
slice: [2 2 3 4], len: 4, cap: 6, address: 0x14000020120
Map
Actually hashmap
https://github.com/golang/go/blob/go1.21.0/src/runtime/map.go
// A header for a Go map.
type hmap struct {
// Note: the format of the hmap is also encoded in cmd/compile/internal/reflectdata/reflect.go.
// Make sure this stays in sync with the compiler's definition.
count int // # live cells == size of map. Must be first (used by len() builtin)
flags uint8
B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
hash0 uint32 // hash seed
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
extra *mapextra // optional fields
}
package main
import (
"fmt"
)
func main() {
m := map[string]int{
"a": 1,
"b": 2,
"c": 3,
}
fmt.Printf("%v\n", m)
m["d"] = 4
fmt.Printf("%v\n", m)
delete(m, "a")
fmt.Printf("%v\n", m)
for key, value := range m {
fmt.Printf("%v\n", key)
fmt.Printf("%v\n", value)
}
clear(m)
fmt.Printf("%v\n", m)
}
output:
map[a:1 b:2 c:3]
map[a:1 b:2 c:3 d:4]
map[b:2 c:3 d:4]
b
2
c
3
d
4
map[]
Also there is mechanism of dynamic expansion for map
. However, I couldn't demostrate it by code so far, since map
does not expose any of the internal pointers to user.
Interface
type iface struct {
tab *itab
data unsafe.Pointer
}
type itab struct {
inter *interfacetype
_type *_type
link *itab
hash uint32 // copy of _type.hash. Used for type switches.
bad bool // type does not implement interface
inhash bool // has this itab been added to hash?
unused [2]byte
fun [1]uintptr // variable sized
}
dynamic type and dynamic value:
package main
import "fmt"
type Speaker interface {
Speak()
}
type Person struct {
Name string
}
func (p Person) Speak() {
fmt.Println("My name is", p.Name)
}
func main() {
var speaker Speaker
p := Person{Name: "Alice"}
speaker = p
speaker.Speak() // output: My name is Alice
}
empty interface:
package main
import "fmt"
func printValue(i interface{}) {
fmt.Println(i)
}
func main() {
printValue(42) // output:42
printValue("hello") // output:hello
printValue(3.14) // output:3.14
}
Channel
package main
import "fmt"
func main() {
ch := make(chan int, 3)
ch <- 42
ch <- 41
ch <- 40
value := <-ch
fmt.Print(value)
ch <- 29
value1 := <-ch
fmt.Print(value1)
value2 := <-ch
fmt.Print(value2)
value3 := <-ch
fmt.Print(value3)
}
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
go func() {
fmt.Println("Sending data to channel")
ch <- 42
fmt.Println("Data sent")
}()
fmt.Println("Receiving data from channel")
value := <-ch
fmt.Println("Received:", value)
}
output:
Receiving data from channel
Sending data to channel
Data sent
Received: 42