@

概述

定义

Go 官网地址 https://golang.google.cn/ 最新版本1.20.3

Go 官网文档地址 https://golang.google.cn/doc/

Go 源码地址 https://github.com/golang

Golang简称Go,是谷歌开源的编程语言,旨在提供程序员编程效率,易于学习,非常适合团队使用,天然支持高并发,有垃圾收集机制,且自带功能完善健壮的标准库。

Go语言表现力强、简洁、干净、高效。它的并发机制使得其容易编写出充分利用多核和网络机器的程序,其类型系统使程序构造变得灵活和模块化。Go可以快速编译为机器码,并且具有垃圾收集的便利性和运行时反射的强大功能;是一种快速的、静态类型的编译语言,感觉像是一种动态类型的解释语言。

Go语言由于来自全球技术大厂谷歌创造及推动,其生态发展极其迅速,从业界声音看大有可能成为接下来10年内最具统治力的语言,也即是替代Java霸主地位,至于未来是否可以静待结果。至少从目前国内大厂阿里、腾讯、百度、字节的使用趋势极其效应可以看到其迅速扩张的可能,越受开发者喜爱其生态完整就会越好,如果从事企业级开发的伙伴有时间精力建议的话不烦可以开始深入学学Go语言开发。

使用场景

  • 云上和网络的应用:如云计算领域、区块链、并发网络编程,有主要的云提供商强大的工具和api生态系统,用Go构建服务很容易。下面列举小部分流行包:

    • cloud.google.com/go
    • aws/client
    • Azure/azure-sdk-for-go
  • Cli命令行接口:cli是纯文本的。云和基础设施应用程序主要基于cli,这样易于自动化和远程功能。使用流行的开放源码包和健壮的标准库,可以使用Go创建快速而优雅的cli。下面列举小部分流行包:
    • spf13/cobra
    • spf13/viper
    • urfave/cli
    • delve
    • chzyer/readline
  • Web开发:Go支持快速和可扩展的web应用程序。下面列举小部分流行包:
    • net/http
    • html/template
    • flosch/pongo2
    • database/sql
    • elastic/go-elasticsearch
  • 开发运营和网站可靠性工程(云原生运维方向,特别是基于k8s的运维开发):Go拥有快速的构建时间、简洁的语法、自动格式化器和文档生成器,可以同时支持DevOps和SRE。下面列举小部分流行包:
    • open-telemetry/opentelemetry-go
    • istio/istio
    • urfave/cli

Go 安全

Go语言编写安全可靠的软件,主要有如下信息:

  • Go安全策略:解释了如何向Go团队报告Go标准库和子库中的安全问题。
  • Go安全发布:Go版本历史包含了过去安全问题的发布说明。根据发布策略发布了两个最新的Go主要版本的安全补丁。
  • Go漏洞管理:支持帮助开发人员找到可能影响其Go项目的已知公共漏洞。
  • Go Fuzzing:提供一种自动测试,持续地操作程序的输入以发现错误。
  • Go加密:Go加密库是Go标准库和子库中的crypto/…和golang.org/x/crypto/…包,并遵循这些原则开发。

使用须知

搜索工具

Go 开发包搜索网站 https://pkg.go.dev/

先安装最新版本的Go。有关下载和安装Go编译器、工具和库的说明,请自行查找安装文档,版本下载(1.20.3),https://golang.google.cn/dl/

由于之前使用1.20.2安装,安装后查看版本

开发过程有需要了解相当包的使用,可以在Go开发官网上查询,这也是一个良好学习和使用方式。

IDE集成开发工具可以选择JetBrains的GoLand,一个扩展支持JavaScript, TypeScript和数据库的Go IDE,JetBrains Go地址

Go基础命令

# 通过命令行输入go可以查看支持命令
go
go help build

  • go bug:打开Bug报告。
  • go build:用于编译指定的源码文件或代码包以及它们的依赖包。常用
  • go clean:移除当前源码包和关联源码包里面编译生成的文件,即删除掉执行其它命令时产生的一些文件和目录,go 命令会在临时目录中构建对象,因此 go clean 主要关注其他工具或手动调用 go build 留下的对象文件。常用
  • go doc:打印与由其参数(包、const、func、类型、var、方法或结构字段)标识的项目相关联的文档注释。
  • go env:打印Go语言的环境信息。
  • go fix:把指定代码包的所有Go语言源码文件中的旧版本代码修正为新版本的代码。
  • go fmt:go程序格式化,自动对齐、空格等。如果用了IDE这个命令就不需要了。
  • go generate:⽣成由现有⽂件中的指令描述的运⾏命令。这些命令可以运⾏任何进程,但⽬的是创建或更新 Go 源文件。
  • go get:根据要求和实际情况从互联网上下载或更新指定的代码包及其依赖包,并对它们进行编译和安装。常用
  • go install:用于编译并安装指定的代码包及它们的依赖包。常用
  • go list:列出指定的代码包的信息。
  • go mod
    • go mod init:生成go.mod文件。常用
    • go mod download :下载go.mod文件中指明的所有依赖。
    • go mod tidy:整理现有的依赖。常用
    • go mod graph:查看现有的依赖结构。
    • go mod edit:编辑go.mod文件。
    • go mod vendor :导出项目所有的依赖到vendor目录。
    • go mod verify:校验一个模块是否被篡改过。
    • go mod why:查看为什么需要依赖某模块。
  • go work:跨文件目录操作本地包、多个mod模块包调用、本地测试。
  • go run:可以编译并运行命令源码文件,并把编译后的可执行文件存放到临时工作目录。常用
  • go test:用于以代码包为单位对Go语言编写的程序进行测试。常用
  • go tool:执行go自带的工具。go tool pprof对cpu、内存和协程进行监控;go tool trace跟踪协程的执行过程。
  • go version:打印 Go 可执⾏⽂件的构建信息。
  • go vet:用于检查Go语言源码中静态错误的简单工具。

标准库

Go 标准库 https://golang.google.cn/pkg/

精心策划的Go项目列表 https://github.com/golang/go/wiki/Projects

目前官方提供190多种标准库包(包括cmd包),涵盖大部分的使用场景,如压缩、加密、数据库、编码、异常、画图、打印、IO操作、网络、操作系统、反射HTML模版等,可以先大概看下官方每个包功能大体说明,需要使用某些功能细节时再具体查看官网。相对于标准库,其他包也称为子库,这些包也是Go项目的一部分,但在Go主干之外。它们是在比Go内核更宽松的兼容性要求下开发的。可以用“go get”安装它们。

基础语法

Effective Go 概览

Go是一门新语言,尽管它借鉴了现有语言的思想,但它具有不同寻常的特性,使有效的Go程序与用其相关语言编写的程序在性质上有所不同。直接将c++或Java程序翻译成Go不太可能产生令人满意的结果。重要的是要先了解它的性质和习惯用法,了解用Go编程的既定约定比如命名、格式、程序结构等等。比如拿分号(Semicolons)来说,像C一样,Go的形式语法使用分号来终止语句,但与C不同的是,这些分号不会出现在源代码中。相反,词法分析器使用一个简单的规则在扫描时自动插入分号,因此输入文本基本上没有分号,也即是在Go语言中不需要采用分号结尾。

命名规范

Go语言核心宗旨就是简洁,在Go语言的相关命名也是推荐如此,命名规则涉及变量、常量、全局函数、结构、接口、方法等的命名,从语法层面进行了以下限定;任何需要对外暴露的名字必须以大写字母开头类似public,不需要对外暴露的则应该以小写字母开头类似private。

  • 一般命名:推荐驼峰命名方式,如userManger或UserManager;单词缩写默认全大写或全小写,如userID、baiduCDN、id、cdn。
  • 项目名:小写,多个单词建议采用中划线分隔,比如github.com/gin-gonic。
  • 包名:package的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,尽量和标准库不要冲突。包名应该为小写单词,不要使用下划线或者混合大小写,统一使用单数形式。如domain、main。
  • 文件名:文件命名一律采用小写,见名思义,测试文件以test.go结尾,如stringutil.go, stringutil_test.go。
  • Local变量:保持简短;如索引采用i而不采用index,reader简写r,buffer简写为b;避免冗余,命名不要和上下文重叠,在方法体内变量名count 会比runeCount更简洁,在map的上下文下可以简写:v,ok=m[k]。
func RuneCount(b []byte) int {
count := 0
for i := 0; i < len(b); {
if b[i] < RuneSelf {
i++
} else {
_, n := DecodeRune(b[i:])
i += n
}
count++
}
return count
}
func Read(b *Buffer, p []byte) (n int, err error) {
if b.empty() {
b.Reset()
}
n = copy(p, b.buf[b.off:])
b.off += n
return n, nil
}
  • 结构体:名词或名词短语,如Account、Book,避免使用Manager这样的。 如果该数据结构需要序列化,如json, 则首字母大写, 包括里面的字段。
type Host struct {
Port string `json:"port"`
Address string `json:"address"`
}
  • 接口:接口单个函数的接口名以 er 为后缀,两个函数的接口名可以综合两个函数名,三个以上函数的接口名类似于结构体名。
type Reader interface {
Read(p []byte) (n int, err error)
}
type WriteFlusher interface {
Write([]byte) (int, error)
Flush() error
}
type Car interface {
Start()
Stop()
Drive()
}
  • 方法:动词或动词短语;如果是结构体方法,那么 Receiver 的名称应该缩写, 要么都使用值, 要么都用指针;一般用一个或两个字母(优先r);对于Receiver命名应该统一, 要么都使用值, 要么都用指针,如果 Receiver 是指针可统一使用p。
func (b *Buffer) Read(p []byte) (n int, err error){
}
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request){
}
func (r Rectangle) Size() Point{
}
func (f foo) method() {
}
func (p *foo) method() {
}

Go没对get/set方法特别支持,必要的时候可以自己定义,Go对get有不同建议,如

// 推荐
p.FirstName()
// 不推荐
p.GetFirstName()
  • error:自定义error命名通常以 “名称+Error” 作为结构体的名字,变量时会用简写err + 名称。
type TypeError struct {
Errors []string
}
ErrShortDst = errors.New("transform: short destination buffer")
  • 常用缩写
src = source
srv = server
arg = argument
conn = connect, connection
attr = attribute
abs = absolute
min = minimum
len = length
auth = authenticate
buf = buffer
ctl = control
ctx = context
str = string
msg = message
fmt = format
dest = destination
diff = difference
orig = original
recv = receive
ref = reference
repo = repository
util = utility

注释

Go提供C风格的/* */块注释和c++风格的//行注释。行注释是常态;块注释主要作为包注释出现,但在表达式中或禁用大量代码时很有用。

变量

在Go语言中,变量被显式声明并被编译器用来检查函数调用的类型正确性;var声明1个或多个变量。

package main

import "fmt"

func main() {

    var a = "initial"
fmt.Println(a) var b, c int = 1, 2
fmt.Println(b, c) var d = true
fmt.Println(d) var e int
fmt.Println(e) f := "apple"
fmt.Println(f)
}

常量(const)

Go支持字符常量、字符串常量、布尔常量和数值常量;const声明一个常数值。

package mainimport (    "fmt"    "math")const s string = "constant"func main() {    fmt.Println(s)    const n = 500000000    const d = 3e20 / n    fmt.Println(d)    fmt.Println(int64(d))    fmt.Println(math.Sin(n))}

控制结构

  • 循环(For):for是Go唯一的循环结构。
package mainimport "fmt"func main() {    i := 1    for i <= 3 {        fmt.Println(i)        i = i + 1    }    for j := 7; j <= 9; j++ {        fmt.Println(j)    }    for {        fmt.Println("loop")        break    }    for n := 0; n <= 5; n++ {        if n%2 == 0 {            continue        }        fmt.Println(n)    }}

  • 选择(If/Else):在Go中没有三元if,所以即使对于基本条件,也需要使用完整的if语句。
package mainimport "fmt"func main() {    if 7%2 == 0 {        fmt.Println("7 is even")    } else {        fmt.Println("7 is odd")    }    if 8%4 == 0 {        fmt.Println("8 is divisible by 4")    }    if num := 9; num < 0 {        fmt.Println(num, "is negative")    } else if num < 10 {        fmt.Println(num, "has 1 digit")    } else {        fmt.Println(num, "has multiple digits")    }}

  • Switch:跨多个分支表达条件。
package mainimport (    "fmt"    "time")func main() {    i := 2    fmt.Print("Write ", i, " as ")    switch i {    case 1:        fmt.Println("one")    case 2:        fmt.Println("two")    case 3:        fmt.Println("three")    }    switch time.Now().Weekday() {    case time.Saturday, time.Sunday:        fmt.Println("It's the weekend")    default:        fmt.Println("It's a weekday")    }    t := time.Now()    switch {    case t.Hour() < 12:        fmt.Println("It's before noon")    default:        fmt.Println("It's after noon")    }    whatAmI := func(i interface{}) {        switch t := i.(type) {        case bool:            fmt.Println("I'm a bool")        case int:            fmt.Println("I'm an int")        default:            fmt.Printf("Don't know type %T\n", t)        }    }    whatAmI(true)    whatAmI(1)    whatAmI("hey")}

数据类型

  • 数组(Arrays):数组是特定长度的元素的编号序列。单在典型的Go代码中,切片更为常见,后面介绍。
package mainimport "fmt"func main() {    var a [5]int    fmt.Println("emp:", a)    a[4] = 100    fmt.Println("set:", a)    fmt.Println("get:", a[4])    fmt.Println("len:", len(a))    b := [5]int{1, 2, 3, 4, 5}    fmt.Println("dcl:", b)    var twoD [2][3]int    for i := 0; i < 2; i++ {        for j := 0; j < 3; j++ {            twoD[i][j] = i + j        }    }    fmt.Println("2d: ", twoD)}

  • 切片(Slices):是Go中的一种重要数据类型,它为序列提供了比数组更强大的接口。
package mainimport "fmt"func main() {    s := make([]string, 3)    fmt.Println("emp:", s)    s[0] = "a"    s[1] = "b"    s[2] = "c"    fmt.Println("set:", s)    fmt.Println("get:", s[2])    fmt.Println("len:", len(s))    s = append(s, "d")    s = append(s, "e", "f")    fmt.Println("apd:", s)    c := make([]string, len(s))    copy(c, s)    fmt.Println("cpy:", c)    l := s[2:5]    fmt.Println("sl1:", l)    l = s[:5]    fmt.Println("sl2:", l)    l = s[2:]    fmt.Println("sl3:", l)    t := []string{"g", "h", "i"}    fmt.Println("dcl:", t)    twoD := make([][]int, 3)    for i := 0; i < 3; i++ {        innerLen := i + 1        twoD[i] = make([]int, innerLen)        for j := 0; j < innerLen; j++ {            twoD[i][j] = i + j        }    }    fmt.Println("2d: ", twoD)}

  • 映射(Maps):Go内置的关联数据类型,在其他语言中有时称为哈希或字典。
package mainimport "fmt"func main() {    m := make(map[string]int)    m["k1"] = 7    m["k2"] = 13    fmt.Println("map:", m)    v1 := m["k1"]    fmt.Println("v1:", v1)    v3 := m["k3"]    fmt.Println("v3:", v3)    fmt.Println("len:", len(m))    delete(m, "k2")    fmt.Println("map:", m)    _, prs := m["k2"]    fmt.Println("prs:", prs)    n := map[string]int{"foo": 1, "bar": 2}    fmt.Println("map:", n)}

迭代(range)

Range遍历各种数据结构中的元素

package mainimport "fmt"func main() {    nums := []int{2, 3, 4}    sum := 0    for _, num := range nums {        sum += num    }    fmt.Println("sum:", sum)    for i, num := range nums {        if num == 3 {            fmt.Println("index:", i)        }    }    kvs := map[string]string{"a": "apple", "b": "banana"}    for k, v := range kvs {        fmt.Printf("%s -> %s\n", k, v)    }    for k := range kvs {        fmt.Println("key:", k)    }    for i, c := range "go" {        fmt.Println(i, c)    }}

函数

Go函数返回值需要显式返回,即它不会自动返回最后一个表达式的值。有多个相同类型的连续参数时可以省略类型相似的参数的类型名称,直到声明该类型的最后一个参数。

package main

import "fmt"

// 多个参数
func plus(a int, b int) int { return a + b
}
// 多个相同类型参数
func plusPlus(a, b, c int) int {
return a + b + c
}
// 多个返回值
func vals() (int, int) {
return 3, 7
}
// 可变参数
func sum(nums ...int) {
fmt.Print(nums, " ")
total := 0 for _, num := range nums {
total += num
}
fmt.Println(total)
}
// 闭包,Go支持匿名函数,它可以形成闭包。当想要内联定义一个函数而不必命名它时可以使用匿名函数很。
func intSeq() func() int {
i := 0
return func() int {
i++
return i
}
}
// 递归函数
func fact(n int) int {
if n == 0 {
return 1
}
return n * fact(n-1)
} func main() { res := plus(1, 2)
fmt.Println("1+2 =", res) res = plusPlus(1, 2, 3)
fmt.Println("1+2+3 =", res) a, b := vals()
fmt.Println(a)
fmt.Println(b) _, c := vals()
fmt.Println(c) sum(1, 2)
sum(1, 2, 3) nums := []int{1, 2, 3, 4}
sum(nums...) nextInt := intSeq() fmt.Println(nextInt())
fmt.Println(nextInt())
fmt.Println(nextInt()) newInts := intSeq()
fmt.Println(newInts()) fmt.Println(fact(7)) var fib func(n int) int fib = func(n int) int {
if n < 2 {
return n
} return fib(n-1) + fib(n-2)
} fmt.Println(fib(7))
}

指针

Go支持指针,允许在程序中传递对值和记录的引用。

package main

import "fmt"

func zeroval(ival int) {
ival = 0
} func zeroptr(iptr *int) {
*iptr = 0
} func main() {
i := 1
fmt.Println("initial:", i) zeroval(i)
fmt.Println("zeroval:", i) zeroptr(&i)
fmt.Println("zeroptr:", i) fmt.Println("pointer:", &i)
}

字符串和符文

Go字符串是字节的只读切片。该语言和标准库将字符串特殊地视为UTF-8编码文本的容器。在其他语言中,字符串是由“字符”组成的。在go中,字符的概念被称为符文——它是一个表示Unicode码点的整数。

package main

import (
"fmt"
"unicode/utf8"
) func main() { const s = "สวัสดี" fmt.Println("Len:", len(s)) for i := 0; i < len(s); i++ {
fmt.Printf("%x ", s[i])
}
fmt.Println() fmt.Println("Rune count:", utf8.RuneCountInString(s)) for idx, runeValue := range s {
fmt.Printf("%#U starts at %d\n", runeValue, idx)
} fmt.Println("\nUsing DecodeRuneInString")
for i, w := 0, 0; i < len(s); i += w {
runeValue, width := utf8.DecodeRuneInString(s[i:])
fmt.Printf("%#U starts at %d\n", runeValue, i)
w = width examineRune(runeValue)
}
} func examineRune(r rune) { if r == 't' {
fmt.Println("found tee")
} else if r == 'ส' {
fmt.Println("found so sua")
}
}

结构体(struct)

Go的结构体是字段的类型化集合,将数据分组形成记录;结构体是可变的。

package main

import "fmt"

type person struct {
name string
age int
} func newPerson(name string) *person { p := person{name: name}
p.age = 42
return &p
} func main() { fmt.Println(person{"Bob", 20}) fmt.Println(person{name: "Alice", age: 30}) fmt.Println(person{name: "Fred"}) fmt.Println(&person{name: "Ann", age: 40}) fmt.Println(newPerson("Jon")) s := person{name: "Sean", age: 50}
fmt.Println(s.name) sp := &s
fmt.Println(sp.age) sp.age = 51
fmt.Println(sp.age)
}

方法

Go支持在结构类型上定义的方法。方法的接受者可以是结构体也可以是指向结构体的指针。

package mainimport "fmt"type rect struct {	width, height int}func (r *rect) area() int {	return r.width * r.height}func (r rect) perim() int {	return 2*r.width + 2*r.height}func main() {	r := rect{width: 10, height: 5}	fmt.Println("area: ", r.area())	fmt.Println("perim:", r.perim())	rp := &r	fmt.Println("area: ", rp.area())	fmt.Println("perim:", rp.perim())}

接口(interface)

接口是方法签名的命名集合。

package mainimport (    "fmt"    "math")type geometry interface {    area() float64    perim() float64}type rect struct {    width, height float64}type circle struct {    radius float64}func (r rect) area() float64 {    return r.width * r.height}func (r rect) perim() float64 {    return 2*r.width + 2*r.height}func (c circle) area() float64 {    return math.Pi * c.radius * c.radius}func (c circle) perim() float64 {    return 2 * math.Pi * c.radius}func measure(g geometry) {    fmt.Println(g)    fmt.Println(g.area())    fmt.Println(g.perim())}func main() {    r := rect{width: 3, height: 4}    c := circle{radius: 5}    measure(r)    measure(c)}

Go支持嵌入结构体和接口,以表达更丰富的类型组合。

package mainimport "fmt"type base struct {    num int}func (b base) describe() string {    return fmt.Sprintf("base with num=%v", b.num)}type container struct {    base    str string}func main() {    co := container{        base: base{            num: 1,        },        str: "some name",    }    fmt.Printf("co={num: %v, str: %v}\n", co.num, co.str)    fmt.Println("also num:", co.base.num)    fmt.Println("describe:", co.describe())    type describer interface {        describe() string    }    var d describer = co    fmt.Println("describer:", d.describe())}

泛型

Go 1.18 引入了泛型,为 Go 语言带来了更强大的类型系统,使其可以更好地支持各种数据类型和算法。Go 泛型可以应用于各种数据类型和算法,使代码更加通用、简洁、易读和易维护。

package mainimport "fmt"func MapKeys[K comparable, V any](m map[K]V) []K {    r := make([]K, 0, len(m))    for k := range m {        r = append(r, k)    }    return r}type List[T any] struct {    head, tail *element[T]}type element[T any] struct {    next *element[T]    val  T}func (lst *List[T]) Push(v T) {    if lst.tail == nil {        lst.head = &element[T]{val: v}        lst.tail = lst.head    } else {        lst.tail.next = &element[T]{val: v}        lst.tail = lst.tail.next    }}func (lst *List[T]) GetAll() []T {    var elems []T    for e := lst.head; e != nil; e = e.next {        elems = append(elems, e.val)    }    return elems}func main() {    var m = map[int]string{1: "2", 2: "4", 4: "8"}    fmt.Println("keys:", MapKeys(m))    _ = MapKeys[int, string](m)    lst := List[int]{}    lst.Push(10)    lst.Push(13)    lst.Push(23)    fmt.Println("list:", lst.GetAll())}

以下是一些使用 Go 泛型的场景:

  • 集合数据类型:Go 泛型可以方便地定义各种集合数据类型,如栈、队列、链表、二叉树等。下面使用泛型定义栈的例子定义了一个 Stack[T] 类型,表示一个可以存储任意类型 T 的栈。Push 方法用于将一个元素压入栈中,Pop 方法用于弹出栈顶的元素。
  • 算法实现:泛型还可以用于实现各种算法,如排序、查找、字符串匹配等。以下是一个使用泛型实现快速排序的例子:在这个例子中,使用泛型定义 QuickSort 函数,可以对任意类型 T 的切片进行排序。该函数采用经典的快速排序算法实现。

错误(errors)

在Go中,习惯上通过显式的单独返回值来传达错误。这与Java和Ruby等语言中使用的异常以及c中有时使用的重载的单个结果/错误值形成对比。Go的方法可以很容易地看到哪些函数返回错误,并使用用于任何其他无错误任务的相同语言结构来处理它们。

package main

import (
"errors"
"fmt"
) func f1(arg int) (int, error) {
if arg == 42 { return -1, errors.New("can't work with 42") } return arg + 3, nil
} type argError struct {
arg int
prob string
} func (e *argError) Error() string {
return fmt.Sprintf("%d - %s", e.arg, e.prob)
} func f2(arg int) (int, error) {
if arg == 42 { return -1, &argError{arg, "can't work with it"}
}
return arg + 3, nil
} func main() { for _, i := range []int{7, 42} {
if r, e := f1(i); e != nil {
fmt.Println("f1 failed:", e)
} else {
fmt.Println("f1 worked:", r)
}
}
for _, i := range []int{7, 42} {
if r, e := f2(i); e != nil {
fmt.Println("f2 failed:", e)
} else {
fmt.Println("f2 worked:", r)
}
} _, e := f2(42)
if ae, ok := e.(*argError); ok {
fmt.Println(ae.arg)
fmt.Println(ae.prob)
}
}

恐慌(pinic)

恐慌通常意味着事情出乎意料地出错了;大多数情况下,使用它来快速处理在正常操作中不应该发生的错误,或者没有准备好优雅地处理的错误。

package main

import "os"

func main() {

    panic("a problem")

    _, err := os.Create("/tmp/file")
if err != nil {
panic(err)
}
}

推迟(defer)

Defer用于确保函数调用在程序执行的后期执行,通常是出于清理目的。Defer通常用于其他语言中使用的地方,例如ensure和finally。比如用于释放或关闭连接、释放或关闭文件句柄等

package main

import (
"fmt"
"os"
) func main() { f := createFile("d:/tmp/defer.txt")
defer closeFile(f)
writeFile(f)
} func createFile(p string) *os.File {
fmt.Println("creating")
f, err := os.Create(p)
if err != nil {
panic(err)
}
return f
} func writeFile(f *os.File) {
fmt.Println("writing")
fmt.Fprintln(f, "data") } func closeFile(f *os.File) {
fmt.Println("closing")
err := f.Close() if err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
}

恢复(recover)

通过使用内置的recover函数,Go使从恐慌中恢复成为可能。恢复可以阻止因恐慌而中止程序,而是让程序继续执行。

package main

import "fmt"

func mayPanic() {
panic("a problem")
} func main() { defer func() {
if r := recover(); r != nil { fmt.Println("Recovered. Error:\n", r)
}
}() mayPanic() fmt.Println("After mayPanic()")
}

  • 本人博客网站IT小神 www.itxiaoshen.com

云原生时代崛起的编程语言Go基础实战的更多相关文章

  1. 阿里云弹性容器实例产品 ECI ——云原生时代的基础设施

    阿里云弹性容器实例产品 ECI ——云原生时代的基础设施 1. 什么是 ECI 弹性容器实例 ECI (Elastic Container Instance) 是阿里云在云原生时代为用户提供的基础计算 ...

  2. 云原生时代,Java的危与机(周志明)

    说明 本篇文章是转载自周志明老师的文章,链接地址:https://www.infoq.cn/article/RQfWw2R2ZpYQiOlc1WBE 今天,25 岁的 Java 仍然是最具有统治力的编 ...

  3. 云原生时代的Java

    原文链接(作者:周志明):https://time.geekbang.org/column/article/321185 公开课链接:https://time.geekbang.org/opencou ...

  4. 🏆【JVM深层系列】「云原生时代的Java虚拟机」针对于GraalVM的技术知识脉络的重塑和探究

    GraalVM 背景 新.旧编程语言的兴起躁动,说明必然有其需求动力所在,譬如互联网之于JavaScript.人工智能之于Python,微服务风潮之于Golang等等.大家都清楚不太可能有哪门语言能在 ...

  5. 进击的 Java ,云原生时代的蜕变

    作者| 易立 阿里云资深技术专家 导读:云原生时代的来临,与Java 开发者到底有什么联系?有人说,云原生压根不是为了 Java 存在的.然而,本文的作者却认为云原生时代,Java 依然可以胜任&qu ...

  6. 开放下载 | 《Knative 云原生应用开发指南》开启云原生时代 Serverless 之门

    点击下载<Knative 云原生应用开发指南> 自 2018 年 Knative 项目开源后,就得到了广大开发者的密切关注.Knative 在 Kubernetes 之上提供了一套完整的应 ...

  7. [转帖]从 SOA 到微服务,企业分布式应用架构在云原生时代如何重塑?

    从 SOA 到微服务,企业分布式应用架构在云原生时代如何重塑? 2019-10-08 10:26:28 阿里云云栖社区 阅读数 54   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权 ...

  8. 云原生时代 给予.NET的机会

    .NET诞生于与Java的竞争,微软当年被罚款20亿美元. Java绝不仅仅是一种语言,它是COM的替代者! 而COM恰恰是Windows的编程模型.而Java编程很多时候比C++编程要容易的多,更致 ...

  9. CODING —— 云原生时代的研发工具领跑者

    本文为 CODING 创始人兼 CEO 张海龙在腾讯云 CIF 工程效能峰会上所做的分享. 文末可前往峰会官网,观看回放并下载 PPT. 大家上午好,很高兴能有机会与大家分享 CODING 最近的一些 ...

  10. 进击的.NET 在云原生时代的蜕变

    你一定看过这篇文章 <进击的 Java ,云原生时代的蜕变>,  本篇文章的灵感来自于这篇文章.明天就将正式发布.NET Core 3.0, 所以写下这篇文章让大家全面认识.NET Cor ...

随机推荐

  1. 解决com.alibaba.excel.exception.ExcelGenerateException: Can not close IO.

    我在使用easycel导出到zip包中时,出现了这个问题.各种文件输出时产生的问题其实大同小异 查看了一些网上的文章,还有github上关于此bug的issue,总算是理清并解决了. 解决方法一 主要 ...

  2. 记录下老dropbox的使用

    32-bit: wget -O - "https://www.dropbox.com/download?plat=lnx.x86" | tar xzf - 64-bit: wget ...

  3. 【StoneDB 模块介绍】服务器模块

    [StoneDB 模块介绍]服务器模块 一.介绍 客户端程序和服务器程序本质上都是计算机上的一个进程,客户端进程向服务器进程发送请求的过程本质上是一种进程间通信的过程,StoneDB 数据库服务程序作 ...

  4. Rust for Rustaceans: Idomatic Programming for Experienced Developers Chap.2 Types

    翻译的内容如果有不理解的地方或者是其他的差错,欢迎后台回复讨论. 类型在内存中的表示 Rust中的每一个值都有自己的类型(Type).在这一章中,我们将会看到Rust中的类型服务于许多不同的目的,但其 ...

  5. mysql查询增加自增列

    mysql> SELECT a.user, @i:=@i+1 as id FROM user a,(SELECT @i:=0) b; +------------------+------+| u ...

  6. 【c语言】整数拆分

    将一个正整数n拆分成若干个正整数的和(至少两个数,n<=100). 输入格式: 一个正整数n 输出格式: 若干行,每行一个等式(数与数之间要求非降序排列).最后一行给出解的总个数 输入样例: 在 ...

  7. 【故障公告】cc攻击又来了,雪上加霜的三月

    非常非常抱歉!今天 21:20-22:10 左右,肆无忌惮的 cc 攻击又来了,蓄意攻击者很厉害,躲过阿里云云盾的黑洞机制,轻松击垮园子的博客站点,又给大家带来了很大的麻烦,请大家谅解! 今年3月是园 ...

  8. BitBake使用攻略--BitBake的语法知识二

    目录 写在前面 1. BitBake中的任务 2. 任务配置 2.1 依赖 2.1.1 内部任务间的依赖 2.1.2 不同菜谱下的任务间依赖 2.1.3 运行时态下的依赖 2.1.4 递归依赖 2.1 ...

  9. ASP.NET Core - 配置系统之自定义配置提供程序

    4. 自定义配置提供程序 在 .NET Core 配置系统中封装一个配置提供程序关键在于提供相应的 IconfigurationSource 实现和 IConfigurationProvider 接口 ...

  10. SpringBoot笔记--事件监听+启动流程+监控+项目部署

    事件监听 ApplicationContextInitializer SpringApplicationRunListener ApplicationRunner CommandLineRunner ...