// 第 1 周 – Go 中的值、指针和切片
// 运行：go run ./w01/valueref
package main

import "fmt"

// 按值传递：函数得到的是一份副本。
func increment(x int) {
	x = x + 1
}

// 按指针传递：函数得到的是变量的地址。
func incrementPtr(x *int) {
	*x = *x + 1
}

// 在 Go 中可以用指针实现交换。
func swap(a, b *int) {
	*a, *b = *b, *a
}

// 数组（[3]int）是值：传递时整个数组都会被复制。
func incrementFirstArray(t [3]int) {
	t[0]++
}

// 切片（[]int）是一个引用底层数组的小描述符：
// 函数看到的是同样的元素。
func incrementFirstSlice(t []int) {
	t[0]++
}

func main() {
	a := 5
	increment(a)
	fmt.Println("after increment a =", a) // 5

	incrementPtr(&a)
	fmt.Println("after incrementPtr a =", a) // 6

	p := &a // p 是一个指针，它的值是 a 的地址
	fmt.Printf("address of a: %p, *p = %d\n", p, *p)

	x, y := 1, 2
	swap(&x, &y)
	fmt.Println("after swap x, y =", x, y) // 2 1

	arr := [3]int{10, 20, 30}
	incrementFirstArray(arr)
	fmt.Println("array – after incrementFirstArray:", arr) // [10 20 30]

	sl := []int{10, 20, 30}
	incrementFirstSlice(sl)
	fmt.Println("slice – after incrementFirstSlice:", sl) // [11 20 30]

	// 两个切片可以指向同一个底层数组
	other := sl
	other[1] = 0
	fmt.Println("after other[1] = 0, sl =", sl) // [11 0 30]

	// nil 指针：不指向任何地方
	var q *int
	fmt.Println("q == nil ?", q == nil)
	// fmt.Println(*q) // 运行时错误：对 nil 指针解引用
}
