一、语法基础

  1. main函数在main包,每个代码文件中的init函数都将在main函数执行前调用。
  2. 同一文件夹中代码使用同一包名,且一般包与文件夹名一致。
  3. 同一包中的变量和类型、标识符可直接使用,包名类型命名空间,包中每个文件对应一个独立的职责。
  4. 将包导入其他文件中,可通过包名间接访问首字母大写的标识符,所定义的对象也只能访问首字母开头的成员变量或函数。
  5. 所有变量被初始化的零值:数值(0),字符串(""),布尔(false),指针(nil),引用类型(返回nil作为其值,但引用的底层数据结构会初始化为对应的零值)。
  6. Go中的引用类型有:map, slice, channel, func。
  7. 广泛使用指针或引用类型来传递变量,但其指针不支持指针运算。
  8. 函数定义(属于包)和方法定义(属于结构体)的区别
  9. 垃圾回收器GC:

 

二、常用数据结构及使用方法

    1. map: map[key]value

//key类型须支持==和!=运算符,不能为浮点数
var matchers = make(map[string]string)
ages := make(map[string]int),ages := make(map[string]int){}  //空map

//slice语法创建
ages := map[string]int{
    "alice":   31,
    "charlie": 34,
}

访问元素:ages["alice"] = 33
if age, ok := ages["bob"]; !ok { /* ... */ }

//map中的元素不是变量,不能寻址
//遍历(遍历顺序不定)   // 迭代切片里的元素
for name, age := range ages {
    fmt.Printf("%s\t%d\n", name, age)
}

 

  2. 数组:固定长度,较少使用

var arrInt [8]int
td := [...]int{0,4,5,2}
//数组引用(将数组引用或指针传入函数)
func toZero(p *[32]byte){
   for i := range p{
      p[i] = 0
   }
}
func toZero1(p *[32]byte){
   *p = [32]byte{}
}

 

  3. slice: 底层使用数组实现,但长度可扩展,传递切片即引用同一对象

var names []string
for name := range ages {
    names = append(names, name)
}
s := arr[:] //初始化切片为数组arr的引用

//提前给slice分配一个合适的大小,避免内存分配和拷贝
names := make([]string, 0, len(ages)) //创建一个空的slice,容量为len
//在函数间传递切片

 

  4. struct: 结构体或类型

type books struct {
    title string
    author string
    subject string
    id int
}
book := &books {
    title: "Go Lang",
    author: "peter"
}
book := books{"Go", "Peter"}

 

  5. channel:

cStop := make(chan bool, 1)
    // Create an unbuffered channel.
    baton := make(chan int)

  

  6. interface: 接口,可用于实现多态特性,只要某个结构体实现了接口类中的所有方法即可作为该接口的子类

type public interface {
    Topic() string
    Message() *Message
    Ack() error
}

type publication struct {
    d amqp.Delivery
    m *Message
    t string
}
func (p *publication) Ack() error {
    return p.d.Ack(false)
}
func (p *publication) Topic() string {
    return p.t
}
func (p *publication) Message() *Message {
    return p.m
}
func (p publication) Message() *Message {
    return p.m
}
type PubSub struct {
    host string
}
type mock struct{}
//其中mock和PubSub都实现了Publish和Subscribe两个接口
    pubs := []publisher{
        pubsub.New("localhost"),
        &mock{},
    }
    for _, p := range pubs {
        p.Publish("key", "value")
        p.Subscribe("key")
    }

 

 

  8. func: 函数或方法

func add(x, y int) int {
    return x + y
}


func swap(x, y string) (string, string) {
    return y, x
}

func add(x, y int) (z int) { 
    z = x + y
    return
}

func sum(numbers ...int) int {
    s := 0
    for i := range numbers{
        s += i
    }
    return s
}

//匿名函数,闭包
    var v func(a int) int
    v = func(a int) int {
        return a * a
    }
    fmt.Println(v(6))
//两种写法
    v1 := func(i int) int {
        return i * i

    }
    fmt.Println(v1(7))

 

  9. 继承与组合

/*
继承
一个结构体嵌到另一个结构体,称作组合
匿名和组合的区别
如果一个struct嵌套了另一个匿名结构体,那么这个结构可以直接访问匿名结构体的方法,从而实现继承
如果一个struct嵌套了另一个【有名】的结构体,那么这个模式叫做组合
如果一个struct嵌套了多个匿名结构体,那么这个结构可以直接访问多个匿名结构体的方法,从而实现多重继承
*/
type Car struct {
    weight int
    name   string
}
func (p *Car) Run() {
    fmt.Println("running")
}
type Bike struct {
    Car
    cycles int
}

package main

import (
    "fmt"
)

type People struct{}

type People2 struct{}

func (p *People) ShowA() {
    fmt.Println("showA")
    p.ShowB()
}
func (p *People) ShowB() {
    fmt.Println("showB")
}

func (p *People) ShowC() {
    fmt.Println("showC")
}

func (p *People) ShowD() {
    fmt.Println("People:showD")
}

func (p *People2) ShowD() {
    fmt.Println("People2:showD")
}

type Teacher struct {
    People  //组合People
    People2 //组合People2
}

func (t *Teacher) ShowB() {
    fmt.Println("teacher showB")
}
func (t *Teacher) ShowC(arg string) {
    fmt.Println(arg)
}

func main() {
    t := Teacher{}

    //print showA
    //print showB
    t.ShowA()

    //print teacher showB
    t.ShowB()

    //print showB
    t.People.ShowB()

    //print test
    t.ShowC("test")

    //print showC
    t.People.ShowC()

    //因为组合方法中多次包含ShowD,所以调用时必须显示指定匿名方法
    //print People2:showD
    t.People2.ShowD()
}

 

  10. 并发数据结构

//同步等待:
    var wg sync.WaitGroup
    wg.Add(2)
    defer wg.Done()
    wg.Wait()
    runtime.Gosched()
//原子操作:
    atomic.AddInt64(&counter, 1)
    time.Sleep(1 * time.Second)
    atomic.StoreInt64(&shutdown, 1)
    atomic.LoadInt64(&shutdown)
//加锁:
    mutex.Lock()
    mutex.Unlock()

//随机数:
    rand.Seed(time.Now().UnixNano())
    n := rand.Intn(100)    

 

三、常用编程模式或框架

  1. 并发模式

    /*
    1.runner包,调度后台处理任务,监视程序执行时间 【for-select结构】
            通过执行返回可判断是超时、系统中断还是正常完成任务
    2.pool包,有缓冲的通道实现资源池,管理多个协程间共享及独立使用的资源。[一组静态资源,数据库连接或内存缓冲区]
            取得资源,归还资源,归还资源时应加互斥锁
    3.work包,无缓冲通过,保证数据能及时处理,实时交换数据。生产者与消费者模型
    */

  2. 编解码

 

  3. 单元测试和压力测试