跳过正文

【2026版】Go语言基础学习指北

·2367 字·5 分钟
旧拾
作者
旧拾
Java后端开发|全栈工程师
目录

前言:一个 “2026年” 的 Flag
#

实不相瞒,学了几年 Go 语言,每次都是花一天时间看完基础语法,然后就没有然后了。结果隔一段时间再看,又像从头来过。2026 年开年重新立个 flag😅

新的一年我决定不再“从入门到放弃”,而是要彻底拿下这门云原生时代的 C 语言。

为什么是 Go? 在后端开发领域,Go (Golang) 已经成为绝对的硬通货。Docker、Kubernetes、Prometheus、Etcd……这些撑起互联网半壁江山的项目全是由 Go 写成。它拥有 C++ 的性能Python 的开发效率,以及天生的高并发基因


1. 环境搭建与 Hello World 🛠️
#

安装
#

前往 Go 官网Go 语言中文网 下载对应安装包。 推荐使用 VS Code 配合 Go 扩展插件,体验极佳。

验证安装:

go version
# 输出: go version go1.25.x ... (2026.1.9最新版本)

你的第一行 Go 代码
#

Go 强制要求项目结构。新建文件 main.go

package main // 1. package 声明:main 包表明这是一个可执行程序

import "fmt" // 2. import 导入:标准库 fmt (format)

func main() { // 3. func 定义:main 函数是程序入口
    fmt.Println("Hello, 2026!")
}

运行: Go 既可以像脚本一样直接运行,也可以编译成二进制文件。

go run main.go
# 或编译后运行 (跨平台部署神器)
go build -o app main.go && ./app

2. 变量与数据类型:魔鬼在细节中 📝
#

变量声明的“潜规则”
#

Go 对变量极其严格:声明了但未使用的局部变量,会导致编译错误

package main

import "fmt"

func main() {
    // 方式1:标准声明 (带零值)
    // int默认为0, string默认为"", 指针/slice默认为nil
    var age int 

    // 方式2:类型推导
    var name = "Gopher"

    // 方式3:短变量声明 (最常用,仅限函数内部)
    // := 左侧必须至少有一个新变量
    lang, year := "Go", 2026

    fmt.Printf("%s 在 %d 年学习 %s, 年龄 %d\n", name, year, lang, age)
}

流程控制:少即是多
#

Go 只有 for 一种循环,没有 while,没有 do-while

// 1. 标准 For 循环
for i := 0; i < 5; i++ {
    if i == 2 {
        continue
    }
    fmt.Println(i)
}

// 2. 模拟 While 循环
n := 0
for n < 5 {
    n++
}

// 3. 死循环 (常用于轮询或守护进程)
// for { ... }

3. 核心数据结构:数组、切片与 Map 📦
#

切片 (Slice) vs 数组 (Array)
#

这是新手最大的坑。

  • 数组:值类型,长度固定。[3]int[4]int 是不同类型。
  • 切片:引用类型,动态长度。底层是对数组的封装。
// 1. 数组 (很少直接用)
var arr [3]int = [3]int{1, 2, 3}

// 2. 切片 (主流选择)
// 使用 make 创建: make([]类型, 长度, 容量)
s := make([]int, 0, 5) 
s = append(s, 100) // append 会自动处理扩容
s = append(s, 200)

fmt.Println(s) // [100 200]

// 切片操作 [low:high] (左闭右开)
// 注意:切片共享底层数组,修改 subSlice 会影响原 slice
subSlice := s[0:1] 

Map (字典)
#

无序的键值对集合。

⚠️ 避坑指南

  1. Map 必须初始化 (make) 后才能写入,否则 panic。
  2. Map 的遍历顺序是随机的,不要依赖顺序。
m := make(map[string]int)
m["one"] = 1

// 查找键值
// val 是值,ok 是布尔值表示 key 是否存在
if val, ok := m["two"]; ok {
    fmt.Println(val)
} else {
    fmt.Println("key not found")
}

delete(m, "one") // 删除

4. 函数、Defer 与错误处理 🛡️
#

延迟执行 (Defer)
#

defer 是 Go 的一大特色。它会将语句压入栈中,在当前函数返回前逆序执行。常用于资源释放(关闭文件、解锁)。

func readFile() {
    fmt.Println("1. 打开文件")
    // 即使下面发生 panic,这行也会在函数结束前执行
    defer fmt.Println("3. 关闭文件") 
    
    fmt.Println("2. 读取内容")
}
// 输出顺序: 1 -> 2 -> 3

错误处理
#

Go 没有 try-catch。Go 认为错误是业务逻辑的一部分,应该显式处理。

func div(a, b int) (int, error) {
    if b == 0 {
        return 0, fmt.Errorf("除数不能为0")
    }
    return a / b, nil
}

func main() {
    if res, err := div(10, 0); err != nil {
        fmt.Println("Error:", err) // 处理错误
    } else {
        fmt.Println("Result:", res)
    }
}

5. 面向对象:结构体与接口 🏗️
#

Go 没有 class,它通过 Struct(结构体) + Interface(接口) 实现面向对象。这是“组合优于继承”的完美体现。

结构体与方法 (Receiver)
#

type User struct {
    Name string
    Age  int
}

// 值接收者:(u User)
// 修改 u 不会影响原对象,只是一份拷贝
func (u User) SayHi() {
    fmt.Println("Hi,", u.Name)
}

// 指针接收者:(u *User) -> 推荐写法
// 既避免了内存拷贝,又能修改原对象
func (u *User) GrowUp() {
    u.Age++
}

func main() {
    u := &User{Name: "Guo", Age: 18}
    u.GrowUp()
    fmt.Println(u.Age) // 19
}

接口 (Interface):鸭子类型
#

Go 的接口是隐式的。“如果它走起来像鸭子,叫起来像鸭子,那它就是鸭子。” 只要一个类型实现了接口定义的所有方法,它就自动实现了该接口。

type Speaker interface {
    Speak()
}

type Dog struct{}
func (d Dog) Speak() { fmt.Println("汪汪") }

type Cat struct{}
func (c Cat) Speak() { fmt.Println("喵喵") }

func main() {
    // 多态
    animals := []Speaker{Dog{}, Cat{}}
    for _, a := range animals {
        a.Speak()
    }
}

6. 灵魂特性:并发 (Goroutine & Channel) ⚡
#

Go 将并发门槛降到了地板。启动一个协程(Goroutine)只需要 go 关键字。

WaitGroup:优雅的并发等待
#

不要在生产环境用 time.Sleep 来等待协程,要用 sync.WaitGroup

package main

import (
    "fmt"
    "sync"
)

func task(id int, wg *sync.WaitGroup) {
    defer wg.Done() // 3. 任务完成,计数器-1
    fmt.Printf("任务 %d 完成\n", id)
}

func main() {
    var wg sync.WaitGroup

    for i := 1; i <= 3; i++ {
        wg.Add(1) // 1. 计数器+1
        go task(i, &wg) // 2. 启动协程
    }

    wg.Wait() // 4. 阻塞,直到计数器归零
    fmt.Println("所有任务结束")
}

Channel:不要通过共享内存来通信
#

通过通信来共享内存。Channel 是协程之间的管道。

func main() {
    // 创建一个带缓冲的 channel,容量为 2
    ch := make(chan string, 2)

    go func() {
        ch <- "Hello"
        ch <- "Juejin"
        close(ch) // 发送完毕关闭通道
    }()

    // 遍历通道直到关闭
    for msg := range ch {
        fmt.Println("接收:", msg)
    }
}

7. 模块化管理:Go Modules 🧩
#

告别 GOPATH,现在的项目都基于 go.mod

  1. 初始化项目
    go mod init my-project
    
  2. 下载依赖 (如 Gin 框架):
    go get -u github.com/gin-gonic/gin
    
  3. 整理依赖 (自动删除没用的,下载缺少的):
    go mod tidy
    

结语:这次一定行 🏁
#

Go 语言的学习曲线是“前平后陡”。基础语法非常简单,一小时就能上手;但要写出高性能、符合 Go 惯用手法(Idiomatic Go)的代码,需要深入理解 GMP 调度模型GC 机制以及Interface 的设计哲学

2026 年的学习路线建议:

  1. 多写:尝试用 Go 重写你熟悉的 Java 小工具。
  2. Web 框架:玩转 GinEcho
  3. 微服务:了解 gRPCProtobuf

💡 如果觉得这篇“复习笔记”对你有帮助,不妨点赞、收藏支持一下!这次flag绝不倒!