1. 循环体变量

package main

import (
	"fmt"
	"time"
)
func main(){
	tt()
}
func tt() {
	for i := 0; i < 10; i++ {
		go func() {
			time.Sleep(1e3)
			fmt.Println(i)
		}()
	}
	time.Sleep(1e9)
}

  • 这个函数执行的时候 tt中打印出来的是10
  • 原因也是很简单,
    • 因为go在初始化的时候先初始化参数量,
    • 全局先初始参数再看函数,
    • 在函数内部先初始参数再进行运算,
    • 所以 就造成在for执行完后,这里的i是同样的i,以为初始化的参数 i一直会变,但是都是这个变量本身,又因为for循环比内部的函数速度快很多,导致,当for循环进行完了,这些函数还没正式开始运行,然后i就取最终值10了

2. return 和 defer 的执行顺序

  • 在Go语言的函数中return语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。
  • defer语句执行的时机就在返回值赋值操作后,RET指令执行前。

return x

  • 返回值 = x
  • 运行defer
  • RET指令

3. 值的方法和指针的方法

  • 指针的方法和值的方法可以互相调用,因为go会自动帮你

    • 比如指针的方法g()你使用了值来调用那么go会帮你自动取地址相对的如果是 值的方法 go自动帮你取 *
  • 值上面可以有方法 指针上面也是有方法,我们谈的是 关于对象的方法这点先阐述 因为除了struct(对象)其它类型除了 指针和nil都可以有自己的方法 其它类型不讨论

  • 就是指针的方法的时候,那么go会自动帮你取这个对象的,因为指针没办法取得对象 里面的value值,只能去得到,但是go帮你取了,所以你可以使用看似指针直接去值。

4.关于range使用的是复制值的

package main

import "fmt"

func main() {
	a := []int{1, 2, 3}
	for k, v := range a {
// range后面的a 是对于 上面的a的复制值 ,但是由于slice底层array连带变了,所以v值就会产生变化
		if k == 0 {
			a[0], a[1] = 100, 200
			fmt.Print(a)
		}
		a[k] = 100 + v
	}
	fmt.Print(a)

	a1 := [3]int{1, 2, 3}
	for k, v := range a1 {
// 这里的a1 是上面a1的复制值,所以v永远就跟之前的那个样子一样,纵然 真实的a1发生了变化但是复制值是不会变化的
		if k == 0 {
			a1[0], a1[1] = 100, 200
			fmt.Print(a1)
		}
		a1[k] = 100 + v
	}
}

//[100 200 3][101 300 103][100 200 3]

5.简式声明仅可以在函数内部使用

package main
myvar := 1 //error
func main() {
}

6.array 函数的参数

Go 中的数组是数值,因此当你向函数中传递数组时,函数会得到原始数组数据的一份复制。如果你打算更新数组的数据,这将会是个问题。

package main
import "fmt"
func main() {
    x := [3]int{1,2,3}
    func(arr [3]int) {
        arr[0] = 7
        fmt.Println(arr) //prints [7 2 3]
    }(x)
    fmt.Println(x) //prints [1 2 3] (not ok if you need [7 2 3])
}

如果你需要更新原始数组的数据,你可以使用数组指针类型。

package main
import "fmt"
func main() {
    x := [3]int{1,2,3}
    func(arr *[3]int) {
        (*arr)[0] = 7
        fmt.Println(arr) //prints &[7 2 3]
    }(&x)
    fmt.Println(x) //prints [7 2 3]
}

另一个选择是使用 slice 。即使你的函数得到了 slice 变量的一份拷贝,它依旧会参照原始的数据。


package main
import "fmt"
func main() {
    x := []int{1,2,3}
    func(arr []int) {
        arr[0] = 7
        fmt.Println(arr) //prints [7 2 3]
    }(x)
    fmt.Println(x) //prints [7 2 3]
}

7.在 slice 和 array 使用“range”语句时的出现的不希望得到的值

Bad:

package main
import "fmt"
func main() {
    x := []string{"a","b","c"}
    for v := range x {
        fmt.Println(v) //prints 0, 1, 2
    }
}

Good:


package main
import "fmt"
func main() {
    x := []string{"a","b","c"}
    for _, v := range x {
        fmt.Println(v) //prints a, b, c
    }
}