这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记;主要复习巩固了Go语言的特点、生态以及最常用的基础语法。
以下所贴代码均已测试运行
介绍GO
优势
- 高性能、高并发
- 语法简单、学习曲线平滑
- 丰富的标准库
- 完善的工具链
- 静态链接
- 快速编译
- 跨平台
- 垃圾回收机制
-
极简的部署
- 直接编译成机器码
- 不依赖其他库(其实就是取消动态库,全部使用静态库链接,一起打包成可执行文件)
- 直接运行、即刻部署
-
静态类型语言
- 就和C/C++一样,典型的后端编译型语言
- 编译器即可检查出隐藏的大部分问题
-
语言层面的并发
- 就是为了并发任务而设计的
-
强大的标准库
- runtime 系统调度机制
- 高效的GC垃圾回收(1.8以后加了三色标记和混合写屏障,效率提升)
-
语法简易而不简单
- 25个关键字
- c语言的简洁基因,内嵌c语法支持
- 面向对象特征
- 跨平台
-
知名开源项目
- 云计算基础设施
- kubernets(k8s)
- docker
- etcd
- consul
- 基础后端软件(存储)
- tidb、influxdb
- 微服务
- go-kit
- micro
- typhon
- 云计算基础设施
第一个GO 程序
Go 作为为并发而生的语言,通过创建 goroutine 进行并发操作,得益于协程的轻量程度,可以轻轻松松完成上万的并发任务
package main
import (
"fmt" // 格式化IO
"time"
)
func goFunc(i int) {
fmt.Println("goroutine", i, "...")
}
func main() {
for i := 0; i < 10000; i++ {
go goFunc(i)
}
time.Sleep(time.Second) // 休眠1s
}
感受一下Go语言简易并强大的并发能力!
// 编译
go build xx.go
// 运行
./xx
// 合并上面的两步
go run xx.go
变量申明
声明单个变量
Go 和其他主流编程语言在声明变量的方式有所不同,Go会将变量类型放在变量名之前,并通过var关键字来声明这个变量。
通常有四种声明方式:
1. 默认参数的变量声明
go var a int
2.带默认值的变量声明
go var b int = 3
3.省略类型的变量声明,编译器会自动推导
go var c = 3.0 var d = 3
4.最常用的方式,利用 := 来进行变量声明,编译器会自动推导
go e := 100
/*
四种变量的声明方式
*/
package main
import (
"fmt"
)
func main() {
// 方法一, 声明变量,默认值为0
var a int
fmt.Println("a = ", a)
fmt.Printf("type of a = %T\n",a)
// 方法二,声明变量,初始化一个值
var b int = 3
fmt.Println("b = ", b)
fmt.Printf("type of b = %T\n",b)
// 方法三,在初始化时,可以省去数据类型,通过值自动匹配(不推荐)
var c = 3.0
fmt.Println("c = ", c)
fmt.Printf("type of c = %T\n",c)
var d = 3
fmt.Println("d = ", d)
fmt.Printf("type of d = %T\n",d)
var str = "hello"
fmt.Println("str = ", str)
fmt.Printf("type of str = %T\n",str)
// 方法四:(最常用的方法)省略关键字var,直接自动匹配
// 效果等同于 var e int = 100 , 声明变量并赋初值
e := 100
fmt.Println("e = ", e)
fmt.Printf("type of e = %T\n",e)
}
tips:
声明全局变量时,方法一到三没有问题,同之前的所有语言一样,而方法四不能声明全局变量( := 只能够在函数体中使用,不能声明全局变量 )
声明多个变量
:
1. 相同类型的变量可以只写一次变量类型:
go var x,y int = 100, 200
2. 或者根本不带类型(:= 也支持该写法):
go var kk, ll = 300,"abc"
3. 甚至可以用小括号定制化:
go var ( vv int = 400 jj bool = true str = "asd" )
package main
import (
"fmt"
)
func main() {
// 声明多个变量
var x,y int = 100, 200
fmt.Println(x," ", y)
var kk, ll = 300,"abc"
fmt.Println(kk, " ", ll)
var (
vv int = 400
jj bool = true
str = "asd"
)
fmt.Println(vv, " ", jj, " ", str)
}
常量的声明与定义
其实就是将关键字改为const
由于Go语言没有枚举类型,所以通过常量const和关键字iota来实现枚举
tips: iota 关键字只能配合const使用,他的声明周期只在const的()范围中
可以在const() 中添加关键字iota, 每行的iota都会累加1 第一行的iota 默认值为 0
具体使用方式可以运行下列代码 :
package main
import (
"fmt"
)
func main() {
// 声明常量(只读属性)
const x int = 100
fmt.Println(x)
// 通过const 变相实现枚举类型
const (
// 可以在const() 中添加关键字iota, 每行的iota都会累加1
// 第一行的iota 默认值为 0
// iota 只会出现在const 的() 中,配合const 使用
BEIJING = iota
SHANGHAI
SHENZHEN
)
fmt.Printf("BEIJING = %d,SHANGHAI = %d,SHENZHEN = %d\n", BEIJING, SHANGHAI, SHENZHEN)
const (
a, b = iota+1,iota+2
c, d
e, f
g,h = iota*2, iota*3
i,k
)
fmt.Println(a," ",b," ",c," ",d)
fmt.Println(e," ",f," ",g," ",h)
fmt.Println(i," ", k)
}
函数
go 语言使用关键字func 来定义一个函数,关键字package 表示当前所在的包的名称,通过import来导入函数所需要的包,函数的返回值是写在参数表的后面,Go还支持多返回值的函数,其中返回值可以匿名。
package main
import (
"fmt"
)
// 返回值写在 () 之后,没有返回值就不写
func fool (a string, b int ) int {
fmt.Println("------fool---------")
fmt.Println("a = ",a," b = ",b)
return 3
}
// 多个匿名返回值
func fool2(a string, b int) (int,string) {
fmt.Println("------fool2---------")
return b,a
}
// 多个带形参名的返回值
// r1 r2 作用域是fool3的整个函数体内
func fool3(a int, b int) (r1 int, r2 int) {
fmt.Println("------fool3---------")
fmt.Println(r1, " ", r2) // r1 r2 属于函数的形参,初始化默认值(0)
r1 = b
r2 = a
return r1,r2
}
// 如果返回值是同类型,类型可以合并写
func fool4(a int, b int) (r1,r2 int) {
fmt.Println("------fool4---------")
r1 = 3
r2 = 4
return r1, r2
}
func main() {
a := fool("ab",5);
fmt.Println(a);
ret1,ret2 := fool2("cd",10)
fmt.Println(ret1," ",ret2)
ret3,ret4 := fool3(1,2)
fmt.Println(ret3," ", ret4)
ret5,ret6 := fool4(1,2)
fmt.Println(ret5," ", ret6)
}
错误处理
go 语言没有warning和异常捕获这种机制,只有error,标准库提供了errors包,使得所有的error可以使用if else 来判断处理,标准库中大量使用到函数返回一个error这种设计,
package main
import (
"errors"
"fmt"
)
func testError(data string) (a string, err error) {
if data == "str" {
return data,nil
} else {
return "",errors.New("this is error")
}
}
func main() {
var a string = "tr"
data, err := testError(a)
if err == nil {
fmt.Println("data is",data)
} else {
fmt.Println(err)
}
}