[ Golang编程基础3 | 青训营笔记]

83 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天

【后端专场 学习资料一】第五届字节跳动青训营 - 掘金 (juejin.cn)

前言 · Go语言圣经 (studygolang.com)

‍⁢⁤‌⁣‬‌⁡⁡⁣⁤‬‌⁣⁣⁡⁣‍‌⁡⁣⁢⁡‬⁡⁣⁡⁤⁡‌⁢⁤‍⁢Go 语言上手 - 基础语法 .pptx - 飞书云文档 (feishu.cn)

结构体

  1. 结构体定义语法

    type structName struct {
        // 结构体内部可以申明任何类型,包括结构体和接口
    	field1 type1
        field2 type2
    	...
    }
    
  2. 结构体申明语法

    type T struct{
        a int
        b int
    }
    // var申明:会分配内存,并零值化内存,变量类型是结构体类型
    var s T
    s.a = 5
    s.b = 6
    // new申明:分配内存,并返回指向已分配内存的指针
    var t *T
    t = new(T)
    t.a = 5
    t.b = 6
    
  3. 选择器(selector):无论变量是一个结构体类型还是一个结构体类型指针,选择器都会都使用同样的 选 择器符(selector-notation) 来引用结构体的字段

  4. 结构体构造工厂:因为Go没有像面向对象语言的那种构造函数,因此一般对于结构体都会写一个构造工厂

    // 结构体定义
    type File struct {
    	fd int // 文件描述符
    	name string // 文件名
    }
    // 构造工厂
    func NewFile(fd int, name string) *File {
    	if fd < 0 {
    		return nil
        }
    	return &File{fd, name}
    }
    //初始化操作
    f := NewFile(10, "./test.txt")
    
  5. 结构体的方法

    • 一个类型加上它的方法等价于面向对象中的一个类
    • 结构体定义和方法可以不在同一个源码文件,但必须在同一个包下
    • 类型 T(或 *T)上的所有方法的集合叫做类型 T(或 *T)的方法集
    • 方法不运行重载,但是同个包下,不同结构体的方法允许重名

接口

  1. 接口定义语法

    type Namer interface {
        Method1(param_list) return_type
        Method2(param_list) return_type
        ...
    }
    
  2. 约定只包含一个方法的接口命名用er结尾

  3. 接口提供了一种方式来 说明 对象 的行为:如果谁能搞定这件事,它就可以用在这

  4. 接口定义了一组方法(方法集),不能包含变量

  5. 空接口或者最小接口 不包含任何方法,它对实现不做任何要求,类似面向对象语言中的基类

错误处理

  1. Go 有一个预先定义的 error 接口类型

    type error interface {
    	Error() string
    }
    
  2. 定义错误语法

    import errors
    err := errors.New(“math - square root of negative number”)
    
  3. 遇到运行错误是,会触发 panic;自定义panic 可以接收一个做任意类型的参数,通常是字符串

  4. panic 会导致栈被展开直到 defer 修饰的 recover() 被调用或者程序中止

goroutine与channel

不要通过共享内存来通信,而通过通信来共享内存

  1. 协程(goroutine)是Go语言提供的一种用户态线程,从语言层面上就支持了并发

  2. 协程由应用程序创建和管理,通过一个调度器来维护多个协程在内核线程上运行,确保公平的占用CPU资源

  3. 在Go中,goroutine的使用很简单,直接在代码前加上关键字 go

  4. channel 是goroutine之间互相通信的通道,goroutine之间可以通过它发消息和接收消息

  5. 一个channel只能传递一种类型的值,因此申明channel的时候要指定类型

    // 例如
    channel := make(chan int)
    
    // 定义调用者接收数据的channel
    // <-chan 表示数据从通道出来,对于调用者就是得到通道的数据,当然就是接收
    receive_only := make (<-chan int)
    
    // 定义调用者发送数据的channel
    // chan<- 表示数据进入通道,要把数据写进通道,对于调用者就是发送
    send_only := make (chan<- int)
    
    // 可同时发送接收,常用
    send_receive := make (chan int)
    
    // 建立带缓存的channel,防止阻塞
    c := make(chan int, 1024)
    

同步与锁

  1. Go中sync包提供了两种锁类型:sync.Mutex(互斥锁)和sync.RWMutex(读写锁)

  2. 使用Lock()加锁,Unlock()用于解锁m

    var lck sync.Mutex
    func foo() {
    	lck.Lock()
    	defer lck.Unlock()
    	// ...
    }
    
  3. WaitGroup,它用于线程同步,WaitGroup等待一组线程集合完成,才会继续向下执行;每个线程 (goroutine)运行,并在完成后调用Done来使得计数器减一

  4. sync.Once.Do(f func())能保证once只执行一次

  5. sync.map,它是原生支持并发安全的map