Go语言基础入门和语法总结|青训营

31 阅读6分钟

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.govar 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 参数 {
case1:
   // 执行语句1
case2:
   // 执行语句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。