Go语言基础语法

本章将系统介绍Go语言的核心语法元素,包括变量、常量、数据类型、控制流、函数、复合类型、指针、结构体以及错误处理。掌握这些基础后,你将能够编写完整的Go程序。

学习建议:每学习一个语法点,建议手动修改并运行示例代码,加深理解。Go语言语法简洁,但静态类型和并发模型需要适应。

变量与常量

变量声明

Go是静态强类型语言,但支持类型推断。变量声明有多种形式:

变量声明示例
package main

import "fmt"

func main() {
    // 完整声明:var 变量名 类型
    var name string
    name = "Alice"

    // 声明并初始化
    var age int = 30

    // 类型推断(省略类型)
    var city = "New York"

    // 短变量声明(只能在函数内使用,最常用)
    score := 95.5

    // 多变量声明
    var x, y int = 10, 20
    a, b := "hello", true

    // 零值机制(未初始化的变量有默认值)
    var count int       // 0
    var flag bool       // false
    var message string  // ""(空字符串)

    fmt.Println(name, age, city, score, x, y, a, b, count, flag, message)
}

关键点:Go中未使用的变量会导致编译错误;短变量声明 := 不能在全局作用域使用;变量可以重新赋值但不能重复声明。

常量

常量使用 const 关键字声明,其值在编译时确定,不可修改。

const Pi = 3.14159
const (
    StatusOK = 200
    StatusNotFound = 404
)
// 枚举式常量(iota)
const (
    Sunday = iota  // 0
    Monday         // 1
    Tuesday        // 2
)

基本数据类型

布尔型:bool,值为 true 或 false。
数值型:int8, int16, int32, int64,uint8, uint16, uint32, uint64,float32, float64,complex64, complex128,以及平台相关的 int, uint, uintptr。
字符串型:string,底层是字节切片,支持中文等UTF-8编码。字符串不可变。
派生类型:指针、数组、切片、结构体、map、函数、接口、通道。
var isActive bool = true
var temperature float64 = 36.6
var username string = "Gopher"
var chars byte = 'A'   // byte 是 uint8 的别名

类型转换

Go不支持隐式类型转换,必须显式转换。

var i int = 42
var f float64 = float64(i)
var u uint = uint(f)
// 字符串与数字转换需使用 strconv 包
import "strconv"
num, _ := strconv.Atoi("123")    // 字符串转整数
s := strconv.Itoa(456)           // 整数转字符串

控制流语句

条件判断:if

Go的if语句无需括号,且可以在条件之前执行一个简单语句。

score := 85
if score >= 90 {
    fmt.Println("A")
} else if score >= 75 {
    fmt.Println("B")
} else {
    fmt.Println("C")
}
// 带初始化语句的 if
if err := process(); err != nil {
    fmt.Println("Error:", err)
}

循环:for

Go只有for循环,没有while和do-while。

// 经典 for
for i := 0; i < 5; i++ {
    fmt.Println(i)
}
// 类似 while
sum := 1
for sum < 100 {
    sum += sum
}
// 无限循环
for {
    // 使用 break 退出
}

分支:switch

Go的switch默认带有break,不需要显式写break;可以使用fallthrough强制执行下一个case。

day := "Saturday"
switch day {
case "Monday", "Tuesday":
    fmt.Println("工作日")
case "Saturday", "Sunday":
    fmt.Println("周末")
default:
    fmt.Println("周中")
}
// 无表达式的 switch 相当于 if-else chain
score := 88
switch {
case score >= 90:
    fmt.Println("A")
case score >= 80:
    fmt.Println("B")
default:
    fmt.Println("C")
}

函数

函数使用func关键字定义,支持多返回值、命名返回值、可变参数。

// 基本函数
func add(a int, b int) int {
    return a + b
}

// 多返回值(常用于错误处理)
func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, fmt.Errorf("除数不能为零")
    }
    return a / b, nil
}

// 命名返回值
func split(sum int) (x, y int) {
    x = sum * 4 / 9
    y = sum - x
    return  // 裸返回,返回 x 和 y
}

// 可变参数
func sum(nums ...int) int {
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}

// 函数作为值(闭包)
func adder() func(int) int {
    sum := 0
    return func(x int) int {
        sum += x
        return sum
    }
}

复合数据类型

数组(长度固定)

var arr [3]int = [3]int{1, 2, 3}
arr2 := [...]int{4, 5, 6}  // 由编译器计算长度
fmt.Println(arr[0])        // 1

切片(动态数组,常用)

slice := []int{1, 2, 3}
slice = append(slice, 4)          // 追加元素
sub := slice[1:3]                 // 切片操作
fmt.Println(len(slice), cap(slice))

// 使用 make 创建切片
s2 := make([]int, 5, 10)          // 长度5,容量10

map(哈希表)

// 声明并初始化
m := map[string]int{
    "apple": 5,
    "pear":  3,
}
m["banana"] = 2
delete(m, "pear")

// 读取安全判断
value, ok := m["orange"]
if ok {
    fmt.Println(value)
} else {
    fmt.Println("不存在")
}

结构体(类似类)

type Person struct {
    Name string
    Age  int
}
// 创建实例
p1 := Person{"Alice", 30}
p2 := Person{Name: "Bob", Age: 25}
// 结构体方法
func (p Person) SayHello() {
    fmt.Printf("Hello, I'm %s\n", p.Name)
}
// 指针接收者(修改结构体)
func (p *Person) SetAge(age int) {
    p.Age = age
}

指针

Go有指针,但不支持指针算术。主要用于传递引用、修改函数外变量。

i := 42
ptr := &i        // ptr 是指向 i 的指针
fmt.Println(*ptr) // 通过 * 解引用
*ptr = 21         // 修改 i 的值

// 函数中使用指针
func zeroVal(val int) {
    val = 0
}
func zeroPtr(ptr *int) {
    *ptr = 0
}
// zeroVal(i) 不会修改原值;zeroPtr(&i) 会修改

错误处理

Go没有异常机制,而是通过返回error类型的值来处理错误。错误处理是Go编程的核心模式。

import "errors"

func divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("division by zero")
    }
    return a / b, nil
}

func main() {
    result, err := divide(10, 0)
    if err != nil {
        fmt.Println("Error:", err)
    } else {
        fmt.Println("Result:", result)
    }
}
最佳实践:总是检查错误;可以使用 fmt.Errorf 包装错误提供更多上下文;Go 1.13+ 支持 errors.Is 和 errors.As 进行错误链判断。

综合示例:命令行计算器

package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    if len(os.Args) != 4 {
        fmt.Println("用法: calc <num1> <op> <num2>")
        return
    }
    a, _ := strconv.ParseFloat(os.Args[1], 64)
    b, _ := strconv.ParseFloat(os.Args[3], 64)
    op := os.Args[2]

    var result float64
    switch op {
    case "+":
        result = a + b
    case "-":
        result = a - b
    case "*":
        result = a * b
    case "/":
        if b == 0 {
            fmt.Println("除数不能为零")
            return
        }
        result = a / b
    default:
        fmt.Println("不支持的操作符")
        return
    }
    fmt.Printf("%g %s %g = %g\n", a, op, b, result)
}

运行示例:go run calc.go 10 + 20 → 输出 10 + 20 = 30。

小结:本章涵盖了Go语言的大部分基础语法。下一章我们将深入讲解Go独有的并发模型——goroutine和channel。