Go语言基础入门和语法总结|青训营
简介
Go是谷歌开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。
Go语言的优点:
-
语法简洁清晰:Go语言的语法简洁且自然,很容易上手,阅读和维护Go代码的难度较低。
-
内置并发支持:Go语言内置了并发支持,通过goroutine和channel可以方便地编写并发程序,使得并发编程变得简单高效。
-
执行效率高:Go语言的编译速度非常快,执行效率也很高,这得益于其优化的编译器和简化的语法。
-
自动垃圾回收
- Go语言的垃圾回收器采用了“三色标记-清扫”的垃圾回收算法。
- 当 heap 内存使用率超过阈值时,就会触发垃圾回收。垃圾回收会短暂停止其他 goroutine 的运行,但这个停顿时间通常很短(微秒级)。
- 支持并发标记技术,可以大幅降低垃圾回收造成的停顿时间。
-
丰富的标准库:Go语言拥有丰富的标准库和框架,包含了常用的数据结构、工具包等,能够满足绝大多数需求。
Go语言的缺点
- 错误处理不灵活:Go语言缺乏通用的异常机制,错误处理需要通过返回错误、显式判断等方式实现,比较繁琐。
- 依赖管理不完善:Go语言的依赖管理相对简单,包管理工具还不够完善和便捷。
- 编程环境:Go语言的编程环境和IDE支持仍不及Java、C#等语言丰富。
- 运行时反射能力有限:Go语言对反射的支持有限,给一些框架带来不便。
- 编译过程可视化程度低:Go语言编译过程的可视化和调试支持不足。
- 发展时间短:相比C、C++、Java等,Go语言发展时间短,生态环境还在完善中。
基础语法
变量声明
使用var
关键字声明变量,var
声明语句可以创建一个特定类型的变量,然后给变量附加一个名字,并且设置变量的初始值。变量声明的一般语法如下:
var 变量名 类型
例如:
var name string
var age int
也可以同时声明多个变量:
var name, age = "John", 30
常量声明
使用 const
关键字声明常量,语法为:
const 常量名 类型 = 值
例如:
const pi = 3.14
const e float64 = 2.71
变量作用域
Go语言中,变量的作用域有以下几种:
包级作用域
在包一级声明的变量拥有包级作用域,可以在整个包的任意文件中使用。
// hello.go
var Version = "1.0" // 包级声明
// main.go
import "hello"
func main() {
println(hello.Version) //可以访问
}
函数作用域
在函数内声明的变量,作用域限定在该函数内,别的函数或包无法访问。
func main() {
var x = 1 // 函数作用域
if true {
y := 2 //块作用域
}
}
块作用域
在代码块({ })内声明的变量,只在该代码块中可见。
if true {
x := 1
}
x // 不可访问x
闭包作用域
闭包函数能访问函数外的变量,产生了闭包作用域。
func outer() {
x := 1
func() {
println(x) // 访问外部x
}()
}
数据类型
Go语言内置的数据类型包括:
- 基本类型:bool、byte、int、uint、float32、float64、complex64、complex128、string
- 派生类型:指针、数组、结构体、切片、字典、管道、函数、接口
条件语句
if语句:
if 条件 {
// 条件满足时执行
} else {
// 条件不满足时执行
}
switch语句:
switch 参数 {
case 值1:
// 执行语句1
case 值2:
// 执行语句2
default:
// 默认执行语句
}
循环语句
for循环语句:
for 初始化语句;条件表达式;后续语句 {
// 循环体
}
while循环语句:
for 条件表达式 {
// 循环体
}
函数
定义一个函数的语法如下:
func 函数名(参数)(返回值){
// 函数体
}
例如:(注意参数定义时类型放在后面,这一点与C/C++大不相同)
func add(x, y int) int {
return x + y
}
包管理
Go语言通过包(package)来组织源代码。
在Go中,包(package)是一种组织代码的方式,用于将相关的功能组合在一起。每个Go源文件开头的 package
声明指定了该文件所属的包。一个包可以包含多个相关的函数、类型和变量等。包的名称一般与包含的文件夹名称相同。
package 包名称
导入包的语法:
import "包路径"
初始化和执行包中的init()函数。
并发编程
Go语言内置并发支持,可以通过goroutine实现轻量级线程。
例如:
go 函数名(参数)
可以启动一个goroutine去异步执行该函数。
通过channel进行goroutine之间的数据通信。
错误处理
Go语言通过内置的error类型来处理错误。
使用errors.New构造错误:
err := errors.New("错误说明")
使用fmt.Errorf组装错误:
err := fmt.Errorf("错误代码%d", code)
匿名函数
匿名函数,也称为lambda函数,是一种省略了函数名的函数。匿名函数通常用于传递给其他函数,或者在需要时直接调用。
匿名函数的语法格式:
func(参数)(返回值){
函数体
}
例如:
func(x, y int){
return x + y
}(1, 2)
上面这个匿名函数接收2个int参数,返回两个参数的和。
匿名函数由于省略了函数名,所以只能在定义时直接调用,通常用来代替很小的函数。
闭包
闭包指一个函数和与其相关的引用环境组合的一个整体。简单来说,闭包=函数+引用环境。
例如:
func outer() func() int {
x := 0
return func() int {
x++
return x
}
}
outer函数返回了一个匿名的内部函数,这个内部函数引用了outer函数的x变量,并且改变了x变量的值。那么该内部函数和它引用的x变量的组合就是一个闭包。
闭包的特点是它保留了原始作用域中的变量,并允许在其他作用域中使用这些变量。
闭包常用于封装某些变量和行为,提供一定的封装性。
测试
Go语言内置了用于测试的测试框架testing
和自带的go test
命令来实现单元测试和性能测试。
编写测试代码和逻辑时,必须创建以Test
开头的函数,这种函数就称为测试函数,例如:
func TestAdd(t *testing.T) {
// 测试代码
}
testing.T
类型拥有 testing框架中的功能方法,我们根据这些方法来编写不同的测试用例。
例如:
func TestSplit(t *testing.T) {
got := Split("a:b:c", ":")
want := []string{"a", "b", "c"}
if !reflect.DeepEqual(want, got) {
t.Errorf("expected:%v, got:%v", want, got)
}
}
在命令行中运行go test
即可运行当前包下所有测试用例:
$ go test
PASS
ok test 0.003s
也可以运行指定的测试函数:
$ go test -run TestSplit
PASS
ok test 0.003s
使用-cover
可以查看测试覆盖率:
$ go test -cover
PASS coverage: 100.0% of statements
ok test 0.003s
使用-bench
可以进行基准测试,可以输出函数的执行时间:
$ go test -bench .
BenchmarkSplit-8 5000000 324 ns/op
PASS
ok test 1.045s
使用-parallel
可以并发执行测试:
$ go test -parallel 4
ok test 2.245s
Go语言内置的测试框架写起来简单高效,可以满足我们日常的单元测试、性能测试等需求。
总结
以上是本人实际使用到的Go语言初级入门语法总结,想更好地使用Go和深入更高级的特性还需要具体官方文档,多查阅手册和资料。实践工程中还需看各种框架的demo。