欢迎来到第二章!在成功搭建了开发环境并运行了第一个 Go 程序之后,现在是时候深入了解 Go 语言的内部构造了。Go 的语法设计深受 C 语言影响,但它摒弃了许多繁琐的历史包袱,力求让代码的阅读和编写变得更加清晰、直观。
本章将带你完成以下任务:
- 掌握 Go 语言的命名规范与可见性规则
- 学习变量、常量及基本数据类型的声明与使用
- 理解 Go 语言中安全且精简的指针机制
- 掌握条件分支与循环控制结构
- 学习函数的定义及多返回值特性
- 了解 Go 的包管理机制与文件结构
2.1 名称(Names)
在 Go 语言中,函数名、变量名、常量名、类型名和包名的命名都遵循一个简单的规则:名称必须以字母或下划线开头,后面可以跟任意数量的字母、数字和下划线。
Go 语言区分大小写,heapSort 和 Heapsort 是两个不同的名称。Go 拥有 25 个关键字(如 if, for, func, var 等),这些不能作为自定义名称。
💡 核心机制:大小写决定可见性(Exported vs Unexported)
在 Go 中,没有 public、private 这样的访问修饰符。标识符的首字母大小写直接决定了它的可见范围:
- 首字母大写(如
Println,Name):是导出的,可以被包外的代码访问(相当于 public)。 - 首字母小写(如
age,calculateSum):是未导出的,只能在包内部使用(相当于 private)。
2.2 变量与常量(Variables & Constants)
变量声明
Go 语言是一门静态强类型语言,变量声明有几种常见方式:
1. 使用 var 关键字(标准声明)
// 声明并初始化
var name string = "Gopher"
// 声明但不初始化(会被赋予零值,如整型的 0,布尔型的 false,字符串的 "")
var age int
2. 短变量声明(推荐用于局部变量)
在函数内部,可以使用 := 进行简短声明,Go 编译器会自动推断类型:
country := "China" // 自动推断为 string
count := 10 // 自动推断为 int
3. 批量声明
var (
a int = 1
b string = "hello"
)
常量声明
使用 const 关键字声明常量,常量的值在编译期就已确定,运行时不可修改。
const Pi = 3.14159
const (
StatusOK = 200
StatusNotFound = 404
)
2.3 基本数据类型(Types)
Go 提供了丰富的基础数据类型:
- 整型:
int8,int16,int32,int64以及对应的无符号整型uint8等。最常用的是int,它在 32 位操作系统上是 32 位,在 64 位系统上是 64 位。 - 浮点型:
float32和float64(推荐使用float64以获得更高精度)。 - 布尔型:
bool,只有true和false两个值。 - 字符串:
string,Go 中的字符串是不可变的字节序列,原生支持 UTF-8 编码。
var isDone bool = true
var price float64 = 99.99
var greeting string = "你好,Go!"
2.4 指针(Pointers)
如果你有 C/C++ 背景,可能会对指针感到恐惧,但请放心:Go 语言的指针安全且简单,不支持指针运算。
指针的值是一个变量的内存地址。
- 使用
&获取变量的地址。 - 使用
*获取指针指向的变量的值(解引用)。
package main
import "fmt"
func main() {
x := 10
p := &x // p 是一个指向 x 的指针,类型为 *int
fmt.Println(*p) // 输出 10 (读取指针指向的值)
*p = 20 // 通过指针修改 x 的值
fmt.Println(x) // 输出 20
}
2.5 控制结构(Control Structures)
Go 的控制结构极度精简,去除了不必要的括号。
if-else 条件判断
条件表达式不需要用小括号 () 括起来,但大括号 {} 是必须的。可以在条件判断前执行一个简短的初始化语句:
if score := 85; score >= 90 {
fmt.Println("优秀")
} else if score >= 60 {
fmt.Println("及格")
} else {
fmt.Println("不及格")
}
for 循环
Go 语言中只有 for 这一种循环结构,它涵盖了 while 和 do-while 的功能。
// 1. 标准的三段式 for 循环
for i := 0; i < 5; i++ {
fmt.Println(i)
}
// 2. 类似 while 的循环
n := 1
for n < 5 {
n *= 2
}
// 3. 无限循环
for {
fmt.Println("无限循环...")
break // 使用 break 跳出循环
}
switch 分支
Go 的 switch 极其灵活,默认情况下,匹配到一个 case 并执行完毕后会自动退出,**不需要写 break**。
os := "darwin"
switch os {
case "darwin":
fmt.Println("Mac OS")
case "linux":
fmt.Println("Linux")
default:
fmt.Println("Other")
}
2.6 函数(Functions)
函数是 Go 语言的“一等公民”。使用 func 关键字定义,参数类型放在参数名之后。
💡 重点特性:Go 函数支持多返回值,这在处理错误时非常有用。
// 定义一个函数,接收两个整型参数,返回相除的商和余数
func divide(a int, b int) (int, int) {
quotient := a / b
remainder := a % b
return quotient, remainder
}
func main() {
q, r := divide(10, 3)
fmt.Printf("商: %d, 余数: %d\n", q, r)
// 如果不需要某个返回值,可以使用空白标识符 "_" 忽略它
_, r2 := divide(15, 4)
fmt.Println("只取余数:", r2)
}
2.7 包和文件(Packages & Files)
Go 语言的代码是通过包(Package)来组织的,包类似于其他语言中的库(Library)或模块(Module)。
- 包声明:每个 Go 源文件的开头都必须有一个
package声明。同一个文件夹下的所有.go文件必须属于同一个包。
package mathutils
- 导入包:使用
import关键字导入需要使用的包。
import (
"fmt"
"math"
)
main包:如果一个项目需要被编译成可执行文件,它必须有一个包含main()函数的main包。作为程序的入口点。init函数:每个包可以包含一个或多个init()函数,这些函数会在包被导入时自动执行,通常用于执行包级别的初始化操作。
2.8 小结
本章你学习了 Go 语言最核心的基础语法:
- 了解了首字母大小写决定可见性这一优雅的设计。
- 掌握了变量、常量和基本数据类型的声明(特别是实用的
:=语法)。 - 认识了 Go 中没有运算负担的安全指针。
- 熟悉了精简的
if、万能的for和无须 break 的switch。 - 编写了支持多返回值的函数。
- 理解了 Go 以包为单位组织代码的哲学。
掌握了这些,你已经具备了编写基础 Go 逻辑的能力。下一步,我们将深入探索 Go 语言中更高级的数据结构,如数组、切片(Slice)、映射(Map)以及结构体(Struct)。
