函数 Main 函数 
每个 Go 程序都应该有个main package 
main package 里的 main 函数是 Go 程序的入口 
Init 函数 
init 函数会在包初始化 时运行,仅运行一次  
谨慎使用 
样例:A 依次依赖 B 和 C ,但 B 也会依赖 C,初始化顺序:C -> B -> A
 
返回值 
支持多值返回 
支持命名返回值:被视为定义在函数顶部的变量  
调用者可以忽略 部分返回值 
 
回调函数 
函数作为参数传入其它函数,并在其它函数内部调用执行
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 func  main ()     DoOperation(1 , increase)     DoOperation(1 , decrease) } func  DoOperation (x int , f func (a, b int )     f(x, 1 ) } func  increase (a, b int )     fmt.Println(a + b) } func  decrease (a, b int )     fmt.Println(a - b) } 
闭包 
闭包为匿名函数,一般没有复用需求
 
不能独立存在 可以赋值给其它变量 
 
可以直接调用 
func(a, b int) { fmt.Println(a + b) }(1, 2) 
 
可以作为函数返回值 
 
 
1 2 3 4 5 defer  func ()     if  r := recover (); r != nil  {         fmt.Println("recovered!" )     } }() 
至此,函数可以作为:参数、返回值、变量
 
方法 
作用在接收者上的函数
 
将上下文保存在 receiver 属性,方法可以直接访问 receiver 属性,进而减少参数的传递
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 type  Human struct  {    firstName, lastName string  } func  (h *Human) string  {    return  h.firstName + ","  + h.lastName } func  main ()     h := new (Human)     h.firstName = "Java"      h.lastName = "Go"      fmt.Println(h.GetName()) } 
值传递 
与 Java 类似
 
Go 只有一种规则:值传递 
函数内修改参数的值不会影响函数外原始变量的值 
可以传递指针参数将变量地址传递给调用函数
Go 会复制该指针作为函数内的地址,但指向同一地址 
 
 
 
1 2 3 4 5 6 7 8 9 10 11 aStr := "new string value"  pointer := &aStr bStr := *pointer fmt.Println(aStr)     fmt.Println(pointer)  fmt.Println(bStr)     aStr = "changed string value"  fmt.Println(aStr)     fmt.Println(pointer)  fmt.Println(bStr)     
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 type  Human struct  {    name string  } func  changeHumanSuccess (h *Human, name string )     h.name = name } func  changeHumanFail (h Human, name string )     h.name = name } func  main ()     h := Human{name: "Java" }     fmt.Println(h)      changeHumanSuccess(&h, "Go" )     fmt.Println(h)      changeHumanFail(h, "Node.js" )     fmt.Println(h)  } 
接口 
接口定义了一组方法集合
 
duck typing:struct 无需显式声明实现 interface一个struct 可以实现多个 interface 
interface 中不能定义属性 
interface 可以嵌套其它 interface 
struct 除了实现 interface 定义的接口外,还可以有额外的方法 
 
interface 可能为 nil,使用 interface 需要先判空,否则可能会触发 nil panic
 
struct 初始化意味着空间分配,对 struct 的引用不会触发 nil panic
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 type  IF interface  {    getName() string  } type  Human struct  {    firstName, lastName string  } type  Car struct  {    factory, model string  } func  (h *Human) string  {    return  h.firstName + ","  + h.lastName } func  (c *Car) string  {    return  c.factory + ","  + c.model } func  main ()     var  ifs []IF     h := new (Human)     h.firstName = "Java"      h.lastName = "Go"      ifs = append (ifs, h)     c := new (Car)     c.factory = "xp"      c.model = "p7"      ifs = append (ifs, c)     for  _, i := range  ifs {         fmt.Println(i.getName())     } } 
反射 
reflect.TypeOf:返回被检查对象的类型reflect.ValueOf:返回被检查对象的值
 
1 2 3 4 5 6 m := make (map [string ]string , 10 ) m["a" ] = "b"  t := reflect.TypeOf(m) fmt.Println(t)  v := reflect.ValueOf(m) fmt.Println(v)  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 type  T struct  {    A string  } func  (t T) string  {    return  t.A } func  (t *T) string ) {    t.A = t.A + s } func  main ()     t := T{A: "a" }     v := reflect.ValueOf(t)     for  i := 0 ; i < v.NumField(); i++ {         fmt.Printf("%d: %v\n" , i, v.Field(i))      }          for  i := 0 ; i < v.NumMethod(); i++ {         fmt.Printf("%d: %v -> %v\n" , i, v.Method(i), v.Method(i).String())     }     result := v.Method(0 ).Call(nil )     fmt.Println(result)                p := reflect.TypeOf(&t)     for  i := 0 ; i < p.NumMethod(); i++ {         fmt.Printf("%d: %v\n" , i, p.Method(i))     } } 
OOP 
Key 
Value 
 
 
可见性控制 
public - 大写 - 跨包使用包内使用 
 
继承 
通过组合实现,内嵌一个或多个 struct 
 
多态 
通过接口实现 
 
JSON 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 type  Human struct  {    Name string  } func  main ()     human := Human{Name: "zhongmingmao" }     marshal := Marshal(&human)     fmt.Println(marshal)      unmarshal := Unmarshal(marshal)     fmt.Println(unmarshal)  } func  Marshal (human *Human) string  {    bytes, err := json.Marshal(human)     if  err != nil  {         println (err)         return  ""      }     return  string (bytes) } func  Unmarshal (marshal string )     human := Human{}     err := json.Unmarshal([]byte (marshal), &human)     if  err != nil  {         println (err)     }     return  human } 
json 使用 map[string]interface{} 和 []interface{} 保存任意类型
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 func  main ()     m := map [string ]interface {}{}     m["name" ] = "bom"      m["height" ] = 183           marshal := Marshal(&m)     fmt.Println(marshal)               Unmarshal(marshal) } func  Marshal (obj *map [string ]interface {}) string  {    bytes, err := json.Marshal(obj)     if  err != nil  {         println (err)         return  ""      }     return  string (bytes) } func  Unmarshal (s string )     var  obj interface {}          err := json.Unmarshal([]byte (s), &obj)     if  err != nil  {         println (err)         return      }          if  m, ok := obj.(map [string ]interface {}); ok {         for  k, v := range  m {             switch  value := v.(type ) {             case  string :                 fmt.Printf("type of %s is string, value is %v\n" , k, value)             case  float64 :                 fmt.Printf("type of %s is float64, value is %v\n" , k, value)             case  interface {}:                 fmt.Printf("type of %s is interface{}, value is %v\n" , k, value)             default :                 fmt.Printf("type of %s is wrong, value is %v\n" , k, value)             }         }     } } 
error 
Go 没有内置的 Exception 机制,只提供了 error 接口
 
1 2 3 type  error  interface  {    Error() string  } 
error 为 interface,处理时需要判断是否为 nil
 
1 2 3 e1 := errors.New("Not Found" ) e2 := fmt.Errorf("code %d" , 404 ) 
借助 struct 实现自定义的 error 归类
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 type  HttpError struct  {    Code Code } type  Code struct  {    Message string  } func  (e *HttpError) string  {    return  e.Code.Message } func  main ()     var  es []error      es = append (es, &HttpError{Code: Code{Message: "Not Found" }}) } 
defer 
函数返回之前执行某个语句或者函数,等同于 Java 的 finally,一般是用来关闭资源(防止资源泄露)
 
1 2 defer  file.Close()defer  mu.Unlock()
defer 的执行顺序类似于一个栈
 
1 2 3 4 5 6 7 8 9 func  main ()     defer  fmt.Printf("Java " )     defer  fmt.Printf("Go " )     defer  fmt.Printf("Rust " )     time.Sleep(time.Second)     fmt.Println("main completed" ) } 
死锁:fatal error: all goroutines are asleep - deadlock!
 
1 2 3 4 5 6 7 8 func  deadLock ()     mutex := sync.Mutex{}     for  i := 0 ; i < 3 ; i++ {         mutex.Lock()                  defer  mutex.Unlock()          fmt.Println(i)     } } 
解决方法:闭包(defer 是在一个函数退出的时候弹栈执行的)
 
1 2 3 4 5 6 7 8 9 mutex := sync.Mutex{} for  i := 0 ; i < 10 ; i++ {  go  func (i int )      mutex.Lock()     defer  mutex.Unlock()      fmt.Println(i)   }(i) } time.Sleep(time.Second) 
panic + recover 
panic:可在系统出现不可恢复错误时主动调用 panic,让当前线程直接 crash保证执行,并把控制权交还给接收到 panic 的函数调用者函数从 panic 中恢复
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 func  main ()     panicFunc()     fmt.Println("main completed" ) } func  panicFunc ()          defer  func ()                   fmt.Println("defer func is called" )                  if  err := recover (); err != nil  {             fmt.Println(err)         }     }()     panic ("a panic is triggered" ) } 
多线程 并发 vs 并行 
并发(concurrency):多个事件间隔发生
 
并行(parallellism):多个事件同时发生
 
协程 对比 进程 
分配系统资源(CPU 时间、内存)的基本单位有独立的内存空间,切换开销大 
 
线程 
线程为进程的一个执行流,是 CPU 调度并能独立运行的基本单位 
同一进程中的多线程共享内存空间,切换开销小 
多线程通信相对方便 
从 Kernel 视角来看,线程本质上是一种特殊的进程
线程与父进程共享:打开的文件、文件系统信息、地址空间、信号处理函数 
 
 
 
协程 
Go 中轻量级线程实现 
Go 在语言层面支持了协程 
 
CSP 
Communicating Sequential Process
 
CSP
两个并发实体通过共享的 channel 进行通信的并发模型 
 
 
goroutine
goroutine 为轻量级线程,并不对应 OS 的线程 – Java
 
goroutine 是一种微线程,能够在发现阻塞后启动新的微线程 
 
 
channel
类似于 Unix 的 Pipe,用于 goroutine 之间的通信和同步 
goroutine 之间解耦,但 goroutine 与 channel 耦合 
 
 
Goroutine vs Thread 
默认内存占用少
goroutine - 2KB 
thread - 8MB 
 
切换开销小
goroutine - 3 个寄存器 
thread - 模式切换(用户态、内核态)、16 个寄存器 
 
并行数量
goroutine - GOMAXPROCS 
thread - 受限于 OS 
 
 
样例 1 2 3 4 5 6 for  i := 0 ; i < 3 ; i++ {  go  func (i int )      fmt.Println(i)   }(i) } time.Sleep(time.Second) 
channel 
channel 是多个 goroutine 之间通讯的管道
 
Java 中的线程间通信是基于共享内存
 
一端发送数据,一端接收数据 
同一时间只有一个 goroutine 可以访问数据
协调 goroutine 的执行顺序 
 
1 2 3 4 5 6 7 8 ch := make (chan  int ) go  func ()   ch <- 1  << 4   }() i := <-ch  fmt.Println(i) 
缓冲区 
基于 channel 的通信是同步的 
当缓冲区满时,数据的发送是阻塞的 
通过 make 关键字创建 channel 时可以定义缓冲区容量(默认为 0)
默认容量为 0,类似于 Java 的 SynchronousQueue 
 
 
 
读阻塞写
 
1 2 3 4 5 6 7 8 9 10 11 12 13 ch := make (chan  int ) go  func ()   time.Sleep(time.Second)   fmt.Println("read start" )   _ = <-ch }() ch <- 1  << 4  fmt.Println("write end" ) 
写阻塞读
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ch := make (chan  int ) go  func ()   _ = <-ch   fmt.Println("read end" ) }() time.Sleep(time.Second) fmt.Println("write start" ) ch <- 1  << 4  time.Sleep(time.Second) 
遍历缓冲区 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 c := 1  << 2  ch := make (chan  int , c) go  func ()   for  i := 0 ; i < c; i++ {     rand.Seed(time.Now().UnixNano())     n := rand.Intn(c)     fmt.Println("put:" , n)     ch <- n   }   close (ch)  }() for  v := range  ch {  fmt.Println("receive:" , v) } 
单向 
双向 -> 单向
 
只写 channel:var writeOnly chan<- intvar readOnly <-chan int
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 func  main ()     ch := make (chan  int )     go  produce(ch)     go  consume(ch)     time.Sleep(time.Second) } func  produce (ch chan <- int )     for  {         ch <- 0      } } func  consume (ch <-chan  int )     for  {         <-ch     } } 
关闭 
channel 无需每次关闭 
关闭的作用:告诉接收者该 channel 再无新数据发送 
只有发送者需要关闭 channel 
 
1 2 3 4 5 6 7 8 9 10 11 12 ch := make (chan  int ) defer  close (ch)go  func ()   ch <- 0  }() go  func ()   if  v, opened := <-ch; opened {     fmt.Println(v)   } }() 
select 
如果所有 channel 都阻塞,则等待或者执行 default,或者随机选择
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 func  main ()     ch1 := make (chan  string )     ch2 := make (chan  string )     go  func ()          time.Sleep(time.Second)         ch1 <- "one"      }()     go  func ()          time.Sleep(1  << 1  * time.Second)         ch2 <- "two"      }()     for  i := 0 ; i < 2 ; i++ {         select  {         case  msg1 := <-ch1:             fmt.Println("receive" , msg1)         case  msg2 := <-ch2:             fmt.Println("receive" , msg2)         }     } } 
timer 
time.Ticker 以固定的时间间隔重复地向 channel C 发送时间值
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 func  main ()     ch := make (chan  int )     timer := time.NewTimer(time.Second)     go  func ()          time.Sleep(1  << 1  * time.Second)         ch <- 0      }()     select  {     case  <-ch:         fmt.Println("receive from ch" )     case  <-timer.C:         fmt.Println("timeout waiting from ch" )     } } 
context 
Context 是设置截止日期、同步信号、传递请求相关值的结构体
 
Context 是 Go 对 goroutine 和 timer 的封装
 
1 2 3 4 5 6 type  Context interface  {  Deadline() (deadline time.Time, ok bool )   Done() <-chan  struct {}   Err() error    Value(key any) any } 
Func 
Desc 
 
 
context.Background 
It is typically used by the main function, initialization, and tests, and as the top-level Context for incoming requests. 
 
context.TODO 
不确定使用什么 context 
 
context.WithDeadline 
超时时间 
 
context.WithValue 
向 context 添加键值对 
 
context.WithCancel 
创建一个可取消的 context 
 
通过关闭 channel 来传递信号,并停止子协程
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 func  main ()     messages := make (chan  int , 10 )     defer  close (messages)          go  func ()          for  i := 0 ; i < 10 ; i++ {             messages <- i         }     }()     done := make (chan  bool )          go  func ()          ticker := time.NewTicker(time.Second)         for  range  ticker.C {             select  {             case  <-done:                 fmt.Println("child process interrupt..." )                 return               default :                 fmt.Printf("receive message: %d\n" , <-messages)             }         }     }()          time.Sleep(1  << 2  * time.Second)     close (done)      time.Sleep(time.Second)     fmt.Println("main process exit" ) } 
通过 context 关闭子协程
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 func  main ()     background := context.Background()     ctx := context.WithValue(background, "name" , "zhongmingmao" )          go  func (c context.Context)          fmt.Println(c.Value("name" ))     }(ctx)          timeout, cancelFunc := context.WithTimeout(background, time.Second)     defer  cancelFunc()     go  func (c context.Context)          for  range  time.NewTicker(time.Second).C {             select  {             case  <-c.Done():                 fmt.Println("child process interrupt..." )                 return              default :                 fmt.Println("enter default" )             }         }     }(timeout)     select  {     case  <-timeout.Done():         time.Sleep(time.Second)         fmt.Println("main process exit" )     } }