New understanding of Go language

"Go, let's go"

Posted by Keal on September 7, 2020

Go简介

Go是google于2007年开始设计,在2009年推出, 是一种静态强类型, 编译型, 并发型语言

著名项目:

  • Docker
  • kubernetes

Go 使用

最近正式开始做一些基于Golang的项目, 随便整理一下:

没有继承, 只有包含关系

​ Go里没有其他语言中class的关键字,也就是说go没有类, go使用struct来实现类似类继承的功能.在类中,你可以用class B继承 class A, 但是在go中, 你建立一个struct B, 其中包含了struct A.

包中的变量引用

​ 首先要知道的是, Go语言中, 大写开头的变量是公共变量, 可以被外部引用, 小写开头的变量是私有变量, 不可被外界访问. 作用类似其他语言中类里的private, public修饰符.

​ 包中的私有变量无法正常被其他包引用,这样在建立包结构时,就很需要注意. 比如你有一个Device->Projector->sony_projector的关系,如果你想在Projector中为sony_projector定义一个base_struct, 但是你又不希望这个base_struct被其他地方调用, 那么你的base_struct就需要与sony_projector在同一个包中. 这样你就不能建立一个Projector包作抽象, 然后建立sony_projector, samsung_projector包去调用Projector包里的私有东西.

异常处理

​ 首先异常处理的目的是改变程序异常状态下的处理流程.

​ Go 没有throw-try-catch机制, 取而代之的是一种panic-recover机制, 两者在设计理念上有比较大的不同. panic触发后,可以被recover获取并进行相应处理. 这种机制建立在defer的使用上(recover需要结合defer来使用)

Panic is a built-in function that stops the ordinary flow of control and begins panicking. When the function F calls panic, execution of F stops, any deferred functions in F are executed normally, and then F returns to its caller. To the caller, F then behaves like a call to panic. The process continues up the stack until all functions in the current goroutine have returned, at which point the program crashes. Panics can be initiated by invoking panic directly. They can also be caused by runtime errors, such as out-of-bounds array accesses.

Recover is a built-in function that regains control of a panicking goroutine. Recover is only useful inside deferred functions. During normal execution, a call to recover will return nil and have no other effect. If the current goroutine is panicking, a call to recover will capture the value given to panic and resume normal execution.

A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Defer is commonly used to simplify functions that perform various clean-up actions.

​ Go 的Panic的想法是用来处理程序出现的严重异常, 如果是一些错误,则可以通过返回值里的error来解决.

When youpanicin Go, you’re freaking out, it’s not someone elses problem, it’s game over man. –Dave Cheney

​ 实际使用情况来说, 在python中, 下层函数,比如一个网络请求的调用或者处理, 可能出现不同的错误情况, 通常我们会自定义一些异常来在特定情况下raise, 上层会通过try-except 来捕获各种异常, 再根据异常类型来处理. 但是在Go中, 异常通常都是通过判断返回的err == nil, 如果需要处理调用的不同的下层函数的错误,可能会通过多if来判断, 如果想统一处理, 虽然可以通过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
// 使用error的写法
func first() error {return nil}
func second() error {return nil}
func third() error {return nil}
func fourth() error {return nil}
func fifth() error {return nil}

func Do() error {
    var err error
    if err = first(); err == nil {
        if err = second(); err == nil {
            if err = third(); err == nil {
                if err = fourth(); err == nil {
                    if err = fifth(); err == nil {
                        return nil
                    }
                }
            }
        }
    }
    return err
}

// panic 写法
func Do2() (err error) {
    defer func(){
        if r:= recover() ; r!= nil{
            err = fmt.Errorf("Error: %+v", r)
        }
    }()
    first2()
    second2()
    third2()
    fourth2()
    fifth2()
    return
}

​ 所以在开发过程中, 我觉得应该事先有一些规范, 例如模块中不要随便panic而是返回error给上层处理.

值得参考的Go编程规范:

Go-CodeReviewComments

Effective Go 中文版

Effective Go

Go Blog

Uber Go 语言编码规范中文版

Reference

Defer, Panic, and Recover

Go 语言踩坑记——panic 与 recover