Web

Go 的类型、编译与基础控制流

Go 是一门静态类型、编译型语言。编写 Go 程序时,变量的类型会在编译阶段确定,源代码也会先被编译成可执行程序。

本文从变量声明开始,依次介绍类型、程序入口以及 ifswitchfor 等基础控制流。

声明变量

Go 会在编译阶段确定变量类型。变量一旦声明,就只能保存对应类型的值。函数内部通常使用 := 声明变量,并让编译器根据右侧的值推导类型:

go
name := "Gopher" // string
age := 25         // int

:= 只能在函数内部使用。需要明确类型或在包级作用域声明变量时,应使用 var

go
var name string = "Gopher"
var age int = 25

声明常量使用 const。常量的值必须能够在编译阶段确定,并且不能在运行过程中重新赋值:

go
const maxRetries = 3
const welcomeMessage = "Hello"

零值

使用 var 声明变量但不提供初始值时,Go 会为它设置对应类型的零值:

go
var count int    // 0
var enabled bool // false
var title string // ""

零值让变量在声明后就处于可用状态。不过,零值是否符合程序需要,仍然要由具体逻辑决定。

类型转换

Go 不会在不同数值类型之间进行隐式转换。参与同一次运算的值类型不同时,需要先显式转换:

go
var count int32 = 10
var total int64 = 20

sum := int64(count) + total

从取值范围较大的类型转换到较小的类型可能丢失数据,转换本身不会自动检查溢出,因此程序仍需验证数据范围。

自定义类型与类型别名

使用 type 可以基于已有类型定义一个新类型:

go
type Meter int64

var distance Meter = 100
var raw int64 = int64(distance)

Meterint64 是不同类型,二者不能隐式混用。新类型还可以拥有自己的方法,适合表达具有明确含义的数据。

= 的声明创建的是类型别名:

go
type Text = string

Text 只是 string 的另一个名称,不会产生新的类型。

Go 程序的入口

Go 源文件以 package 声明开始。可执行程序使用 main 包,并从 main() 函数开始运行:

go
package main

import "fmt"

func main() {
	fmt.Println("Hello, Go")
}

开发时可以直接编译并运行源码:

bash
go run main.go

也可以先生成可执行文件,再运行编译产物:

bash
go build -o app main.go
./app

Go 程序仍然拥有负责垃圾回收、内存分配和并发任务调度的运行时。这个运行时会被链接进编译产物,因此目标环境不需要另外安装 Go 工具链才能运行程序。

条件判断

Go 使用 if 表达条件分支。条件不需要写在括号中,但分支代码必须放在大括号内:

go
label := "disabled"
enabled := true

if enabled {
	label = "enabled"
}

fmt.Println(label)

Go 没有三元表达式。需要根据条件选择值时,直接使用 if 可以让赋值过程保持清晰。

使用 switch 处理多个分支

当同一个值需要匹配多个分支时,可以使用 switch

go
status := "done"

switch status {
case "pending":
	fmt.Println("waiting")
case "done":
	fmt.Println("completed")
default:
	fmt.Println("unknown")
}

每个 case 默认在执行完成后退出 switch,通常不需要额外编写 break

使用 for 循环

Go 只有 for 一个循环关键字。它可以表达常见的计数循环:

go
for i := 0; i < 3; i++ {
	fmt.Println(i)
}

省略初始化语句和结束语句后,for 可以只保留循环条件:

go
retries := 0

for retries < maxRetries {
	retries++
}

省略全部条件则会形成无限循环,需要通过 breakreturn 主动结束:

go
for {
	fmt.Println("running")
	break
}

遍历 Array、Slice 或 Map 时还可以配合 range。这些集合类型及其遍历方式会在后续文章中介绍。

总结

Go 会在编译阶段确定变量类型,并要求不同类型之间进行显式转换。可执行程序从 main() 开始,通过 go rungo build 编译运行。基础控制流则集中在 ifswitchfor 上,语法数量不多,但每种结构都有明确的使用方式。