defer

执行顺序

  1. package main
  2. import "fmt"
  3. func main() {
  4. defer func() {
  5. fmt.Println("1")
  6. }()
  7. defer func() {
  8. fmt.Println("2")
  9. }()
  10. defer func() {
  11. fmt.Println("3")
  12. }()
  13. panic("error ")
  14. }

defer 是后进先出。panic 需要等defer 结束后才会向上传递。 出现panic恐慌时候,会先按照defer的后入先出的顺序执行,最后才会执行panic。
执行结果

  1. 3
  2. 2
  3. 1
  4. panic: error
  5. goroutine 1 [running]:
  6. main.main()

函数混合

  1. package main
  2. import "fmt"
  3. func calc(idx string, a, b int) int {
  4. res := a + b
  5. fmt.Printf("[%s] %d+%d=%d\n",idx,a,b,res)
  6. return res
  7. }
  8. func main() {
  9. a := 1
  10. b := 2
  11. defer calc("1", a, calc("2", a, b))
  12. a = 0
  13. defer calc("3", a, calc("4", a, b))
  14. b = 1
  15. }

执行结果

  1. [2] 1+2=3
  2. [4] 0+2=2
  3. [3] 0+2=2
  4. [1] 1+3=4

Range

for 循环是执行拷贝一个新地址 执行 ,1 不要通过这种变量值取地址 ,2不要通过这个值修改元素属性值

  1. package main
  2. import "fmt"
  3. type User struct {
  4. Id int
  5. Name string
  6. }
  7. func main() {
  8. m := make(map[string]*User)
  9. stus :=[]User{
  10. User{Id:1,Name:"zhang"},
  11. User{Id:2,Name:"li"},
  12. User{Id:3,Name:"wang"},
  13. }
  14. for _,stu :=range stus{
  15. m[stu.Name] = &stu
  16. }
  17. for k,v :=range m{
  18. fmt.Println(k,v)
  19. }
  20. }

都是使用副本的方式。所以m[stu.Name]=&stu实际上一致指向同一个指针, 最终该指针的值为遍历的最后一个struct的值拷贝。 就像想修改切片元素的属性:

  1. package main
  2. import "fmt"
  3. type User struct {
  4. Id int
  5. Name string
  6. }
  7. func main() {
  8. stus :=[]User{
  9. User{Id:1,Name:"zhang"},
  10. User{Id:2,Name:"li"},
  11. User{Id:3,Name:"wang"},
  12. }
  13. for _,stu :=range stus{
  14. stu.Id = stu.Id+1
  15. }
  16. for _,stu :=range stus{
  17. fmt.Println(stu)
  18. }
  19. }

下面的打印结果还是

  1. {1 zhang}
  2. {2 li}
  3. {3 wang}

闭包

闭包捕获的变量和常量是引用传递,不是值传递。

  1. package main
  2. import (
  3. "sync"
  4. "fmt"
  5. )
  6. func main() {
  7. wg := sync.WaitGroup{}
  8. wg.Add(2)
  9. for i := 0; i < 2; i++ {
  10. fmt.Printf("1a=%p\n", &i)
  11. go func() {
  12. fmt.Printf("2a=%p\n", &i)
  13. fmt.Println("i: ", i)
  14. wg.Done()
  15. }()
  16. }
  17. wg.Wait()
  18. }

上面程序执行结果

  1. 1a=0xc000014090
  2. 1a=0xc000014090
  3. 2a=0xc000014090
  4. i: 2
  5. 2a=0xc000014090
  6. i: 2

go func中i是函数参数,与外部for中的i完全是两个变量。 尾部(i)将发生值拷贝,go func内部指向值拷贝地址。引用会执行拷贝操作

  1. package main
  2. import (
  3. "sync"
  4. "fmt"
  5. )
  6. func main() {
  7. wg := sync.WaitGroup{}
  8. wg.Add(2)
  9. for i := 0; i < 2; i++ {
  10. fmt.Printf("1a=%p\n", &i)
  11. go func(i int ) {
  12. fmt.Printf("2a=%p\n", &i)
  13. fmt.Println("i: ", i)
  14. wg.Done()
  15. }(i)
  16. }
  17. wg.Wait()
  18. }

打印结果

  1. 1a=0xc00008e010
  2. 1a=0xc00008e010
  3. 2a=0xc00008e030
  4. i: 1
  5. 2a=0xc000014080
  6. i: 0

Interface

  1. package main
  2. import "fmt"
  3. type People struct{}
  4. func (p *People) foo() {
  5. fmt.Println("people foo")
  6. p.bar()
  7. }
  8. func (p *People) bar() {
  9. fmt.Println("people bar")
  10. }
  11. type Student struct {
  12. People
  13. }
  14. func (t *Student) bar() {
  15. fmt.Println("student bar")
  16. }
  17. func main() {
  18. t := Student{}
  19. t.foo()
  20. }

执行结果

  1. people foo
  2. people bar

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. type People interface {
  6. Foo()
  7. }
  8. type Student struct{}
  9. func (stu *Student) Foo() {
  10. }
  11. func newInstance() People {
  12. var stu *Student
  13. return stu
  14. }
  15. func main() {
  16. a := newInstance()
  17. if a == nil {
  18. fmt.Println("empty value")
  19. } else {
  20. fmt.Println(a)
  21. fmt.Printf("%p\n", a)
  22. }
  23. }

打印结果是

  1. <nil>
  2. 0x0

Select

随机输出

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. func main() {
  7. int_chan := make(chan int, 1)
  8. string_chan := make(chan string, 1)
  9. int_chan <- 1
  10. string_chan <- "hello"
  11. time.Sleep(time.Second)
  12. select {
  13. case value := <-int_chan:
  14. fmt.Println(value)
  15. case value := <-string_chan:
  16. fmt.Println(value)
  17. }
  18. }

Slice

  1. package main
  2. import "fmt"
  3. func main() {
  4. s := make([]int, 3)
  5. s = append(s, 1, 2, 3)
  6. fmt.Println(s)
  7. }

打印结果

  1. [0 0 0 1 2 3]

数组

值类型

当前不会修改数组里面值的内容,修改值需要传递指针

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

需要使用指针

  1. func main() {
  2. x := [3]int{1,2,3}
  3. func(arr *[3]int) {
  4. (*arr)[0] = 7
  5. fmt.Println(arr) //prints &[7 2 3]
  6. }(&x)
  7. fmt.Println(x) //prints [7 2 3]
  8. }

range

range 遍历包含2个值 第一个是当前的数组下标,第二个才是存储的值

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

Strings

字符串修改

字符串是只读形式的字符切片 如果需要修改当前字符里面的字符 需要将字符串转换成
字符切片

  1. x := "text"
  2. x[0] = 'T'
  3. fmt.Println(x)
  1. x := "text"
  2. xbytes := []byte(x)
  3. xbytes[0] = 'T'
  4. fmt.Println(string(xbytes)) //prints Text

字符串不能被赋为”空”

  1. package main
  2. func main() {
  3. var x string = nil //error
  4. if x == nil { //error
  5. x = "default"
  6. }
  7. }
  8. ./hello.go:4: cannot use nil as type string in assignment
  9. ./hello.go:6: invalid operation: x == nil (mismatched types string and nil)

JSON编码

The struct fields starting with lowercase letters will not be (json, xml, gob, etc.) encoded, so when you decode the structure you’ll end up with zero values in those unexported fields.
首字母小写是无法被json 匹配的

  1. package main
  2. import (
  3. "fmt"
  4. "encoding/json"
  5. )
  6. type MyData struct {
  7. One int
  8. two string
  9. }
  10. func main() {
  11. in := MyData{1,"two"}
  12. fmt.Printf("%#v\n",in) //prints main.MyData{One:1, two:"two"}
  13. encoded,_ := json.Marshal(in)
  14. fmt.Println(string(encoded)) //prints {"One":1}
  15. var out MyData
  16. json.Unmarshal(encoded,&out)
  17. fmt.Printf("%#v\n",out) //prints main.MyData{One:1, two:""}
  18. }

无法下载golang.org/x/

第一种方式是使用git clone 下载GitHub的镜像地址

  1. mkdir -p $GOPATH/src/golang.org/x/
  2. cd !$
  3. git clone https://github.com/golang/net.git
  4. git clone https://github.com/golang/sys.git
  5. git clone https://github.com/golang/tools.git
  6. git clone https://github.com/golang/crypto.git

第二种方式推荐使用这种方式 go mod 使用 replace

  1. replace (
  2. golang.org/x/crypto => github.com/golang/crypto v0.0.0-20190325154230-a5d413f7728c
  3. golang.org/x/image => github.com/golang/image v0.0.0-20190321063152-3fc05d484e9f
  4. golang.org/x/sys => github.com/golang/sys v0.0.0-20190402142545-baf5eb976a8c
  5. golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0
  6. )

当前现在有支持了proxy https://goproxy.io
或者命令方式

  1. go env -w GOPROXY=https://goproxy.cn,direct