Go value/reference types
Tags: go
Published: 2023-12-03 18:09:53

In go we have several types, most common are: 

**Numeric Types:**

- int (platform-dependent signed integer)
- int8, int16, int32, int64 (signed integers of specific sizes)
- uint (platform-dependent unsigned integer)
- uint8, uint16, uint32, uint64 (unsigned integers of specific sizes)
- float32, float64 (floating-point numbers)
- complex64, complex128 (complex numbers)

**Boolean Type:**
- bool (true/false values)

**String Type:**
- string (immutable sequence of bytes)

**Derived Types:**
- array (fixed-size sequence of elements of the same type)
- slice (variable-size sequence dynamically built on top of an array)
- map (unordered collection of key-value pairs)
- struct (composite data type that groups together variables of different types)
- channel (communication mechanism between goroutines)

**Pointer Types:**
- *T (a pointer to a value of type T)

**Function Types:**
- func (function types)

**Interface Type:**
- interface (a set of method signatures)


All basic types (Numeric, Boolean, String) along with structs and arrays from the derived types, functions and interfaces are passed by value.

Maps, arrays, slices and channels are passed by reference.

1. Assigning variables is passing by value

```
var a = 10
var b = a

fmt.Printf("a:%p\nb:%p", &a, &b)`
```

> a:0xc0000a4000
b:0xc0000a4008   

2. Providing arguments to functions is passing by value

```
func printFunc() {
	var a = 10
	fmt.Printf("a: %p", &a)
	//Passing in a function creates a new value
	PassByValue(a)
}

func PassByValue(a int) {
	fmt.Printf("f :%p", &a)
}
```


> a :0xc0000120d0a 
f :0xc0000120f0

3. Reassining reference types creates a new value for the variable holding it, but keeps the underlying structure

```	
a := []float64{
		97.5,
		105,
		63.5}

	b := a

	fmt.Printf("The variables have different memory allocations")
	fmt.Print("\n")
	fmt.Printf("a: %p", &a)
	fmt.Print("\n")
	fmt.Printf("b: %p", &b)
	fmt.Print("\n")
	fmt.Print("------------------")
	fmt.Print("\n")
	fmt.Print("\n")
	fmt.Printf("The underlying structure keeps it's reference")
	fmt.Print("\n")
	fmt.Printf("a[0]: %p", &a[0])
	fmt.Print("\n")
	fmt.Printf("b[0]: %p", &b[0])
	fmt.Print("\n")
	fmt.Print("------------------")
	fmt.Print("\n")
	fmt.Print("\n")
	fmt.Printf("Confirming they hold the same values")
	fmt.Print("\n")
	fmt.Printf("a: %v", a)
	fmt.Print("\n")
	fmt.Printf("b: %v", b)

> The variables have different memory allocations
> a: 0xc0000a4000
> b: 0xc0000a4018
> ------------------
> The underlying structure keeps it's reference
> a[0]: 0xc0000a6000
> b[0]: 0xc0000a6000
> ------------------
> Confirming they hold the same values
> a: [97.5 105 63.5]
> b: [97.5 105 63.5] 
```

4. Passing by * and &

'*' - Dereference operator. When it's used as a prefix to a variable it's pulling the value that pointer is pointing to

'&' - Address of operator. When it's used as a prefix to a variable it retrieves the memory address where the variable is stored

```
var a = 5

fmt.Printf("a: %p", &a)
fmt.Print("\n")

passByReferenceFunc(&a)

func passByReferenceFunc(a *int) {
	fmt.Printf("f: %p", a)
}
```

>a: 0xc0000a4000
f: 0xc0000a4000