GoLang:语法、并发与工程实践
Go(又称 Golang)是 Google 于 2009 年发布的开源编译型静态类型语言,由 Robert Griesemer、Rob Pike、Ken Thompson 设计。 目标是兼顾 C 的性能与 Python 的开发效率,内置并发原语(goroutine / channel),特别适合构建网络服务、CLI 工具和云原生应用。
相关文章:GoLang 类型系统与数据结构深度 · GoLang 并发编程 · GoLang 错误处理与 panic-defer · GoLang 标准库速查 · GoLang 工程实践
⚠️ 版本说明:本文以 Go 1.22+ 为基准,所有代码示例均可直接运行。部分特性(泛型
1.18+、range over integers1.22+)在低版本不可用。
目录
| 章节 | 说明 |
|---|---|
| 核心特性 | 设计哲学、与其他语言的对比 |
| 安装与工具链 | 安装、GOPATH/GOROOT、常用命令 |
| 基础语法 | 变量、常量、基本类型、零值 |
| 函数 | 多返回值、命名返回值、变参、defer |
| 流程控制 | if、for、switch、goto |
| 复合类型 | array、slice、map、struct |
| 指针 | 基本用法、与 C 的区别 |
| 方法与接口 | 值/指针接收者、接口、空接口、类型断言 |
| 错误处理 | error 接口、自定义错误、panic/recover |
| 并发 | goroutine、channel、select、sync |
| 包与模块 | package、go mod、常用标准库 |
| 快速参考卡 | 类型速查、内置函数速查 |
核心特性
设计哲学
| 特性 | 说明 |
|---|---|
| 编译型 | 直接编译为机器码,无需运行时,启动极快 |
| 静态类型 | 编译期类型检查,减少运行时错误 |
| 垃圾回收 | 自动内存管理,无需手动 malloc/free |
| 内置并发 | goroutine + channel,并发模型简洁高效 |
| 工具链统一 | go fmt、go test、go build 开箱即用 |
| 依赖极简 | 单二进制输出,无外部动态库依赖 |
| 无继承 | 通过组合(embedding)和接口实现多态 |
与其他语言对比
| 维度 | Go | Java | Python |
|---|---|---|---|
| 编译方式 | 编译为原生二进制 | 编译为字节码(JVM) | 解释执行 |
| 并发模型 | goroutine(M:N 调度) | 线程 | GIL 限制 |
| 类型系统 | 静态、强类型 | 静态、强类型 | 动态、强类型 |
| 启动速度 | 极快(毫秒级) | 慢(JVM 预热) | 快 |
| 内存占用 | 低 | 高 | 中 |
| 泛型 | 1.18+ 支持 | 支持 | 支持 |
安装与工具链
安装
# macOS(推荐 Homebrew)
brew install go
# 验证
go version # go version go1.22.x darwin/arm64
重要环境变量
go env GOROOT # Go 安装目录(标准库所在位置)
go env GOPATH # 工作区目录,默认 ~/go
go env GOMODCACHE # 模块缓存目录,默认 ~/go/pkg/mod
go env GOPROXY # 模块代理,国内推荐设置:
go env -w GOPROXY=https://goproxy.cn,direct
常用工具命令
go run main.go # 编译并运行(开发调试用)
go build . # 编译当前包,生成可执行文件
go build -o app . # 指定输出文件名
go install . # 编译并安装到 $GOPATH/bin
go test ./... # 运行所有测试
go test -v ./... # 详细输出
go test -run TestFoo # 只运行匹配的测试
go fmt ./... # 格式化代码(强制统一风格)
go vet ./... # 静态检查常见错误
go mod tidy # 整理依赖(添加缺失、删除多余)
go get github.com/pkg@v1.2.3 # 添加/升级依赖
go doc fmt.Println # 查看文档
创建第一个项目
mkdir hello && cd hello
go mod init hello # 初始化模块,生成 go.mod
创建 main.go:
package main
import "fmt"
func main() {
fmt.Println("Hello, Go!")
}
go run main.go # 输出:Hello, Go!
基础语法
变量声明
package main
import "fmt"
func main() {
// 方式一:var 声明(显式类型)
var name string = "Alice"
var age int = 30
// 方式二:var 声明(类型推断)
var city = "Beijing"
// 方式三:短变量声明(函数内最常用)
score := 98.5
// 多变量声明
var x, y int = 1, 2
a, b := "hello", true
// 批量声明
var (
host = "localhost"
port = 8080
)
fmt.Println(name, age, city, score, x, y, a, b, host, port)
}
零值(Zero Value)
Go 中所有变量声明后都有默认零值,不存在未初始化的变量:
package main
import "fmt"
func main() {
var i int // 0
var f float64 // 0.0
var b bool // false
var s string // ""(空字符串)
var p *int // nil
fmt.Println(i, f, b, s, p)
}
常量
package main
import "fmt"
// 常量在编译期求值,不可修改
const Pi = 3.14159
const MaxRetry = 3
// iota:枚举常量自动递增
type Weekday int
const (
Sunday Weekday = iota // 0
Monday // 1
Tuesday // 2
Wednesday // 3
)
// iota 的其他用法
const (
KB = 1 << (10 * (iota + 1)) // 1024
MB // 1048576
GB // 1073741824
)
func main() {
fmt.Println(Pi, MaxRetry)
fmt.Println(Sunday, Monday, Tuesday)
fmt.Println(KB, MB, GB)
}
基本类型
| 类型 | 说明 | 零值 |
|---|---|---|
bool | 布尔值 | false |
int / int8/16/32/64 | 有符号整数 | 0 |
uint / uint8/16/32/64 | 无符号整数 | 0 |
float32 / float64 | 浮点数 | 0 |
complex64 / complex128 | 复数 | 0 |
string | UTF-8 字符串(不可变字节序列) | "" |
byte | uint8 的别名 | 0 |
rune | int32 的别名,表示 Unicode 码点 | 0 |
package main
import "fmt"
func main() {
// 类型转换(Go 不做隐式转换,必须显式)
var i int = 42
f := float64(i)
u := uint(f)
fmt.Println(i, f, u)
// 字符串与 []byte 互转
s := "Hello, 世界"
b := []byte(s)
r := []rune(s)
fmt.Println(len(s)) // 13(字节数)
fmt.Println(len(b)) // 13(字节数)
fmt.Println(len(r)) // 9(字符数)
}
函数
基本定义
package main
import "fmt"
// 基本函数
func add(a, b int) int {
return a + b
}
// 多返回值(Go 特色)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("除数不能为零")
}
return a / b, nil
}
// 命名返回值(适合短函数,增加可读性)
func minMax(nums []int) (min, max int) {
min, max = nums[0], nums[0]
for _, v := range nums[1:] {
if v < min {
min = v
}
if v > max {
max = v
}
}
return // naked return,返回命名变量的当前值
}
// 可变参数
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
func main() {
fmt.Println(add(3, 4)) // 7
result, err := divide(10, 3)
if err != nil {
fmt.Println("错误:", err)
} else {
fmt.Printf("%.4f\n", result) // 3.3333
}
lo, hi := minMax([]int{3, 1, 4, 1, 5, 9})
fmt.Println(lo, hi) // 1 9
fmt.Println(sum(1, 2, 3, 4, 5)) // 15
// 展开 slice 传入可变参数
nums := []int{1, 2, 3}
fmt.Println(sum(nums...)) // 6
}
defer
package main
import "fmt"
func main() {
// defer 在函数返回前执行,多个 defer 按 LIFO 顺序执行
defer fmt.Println("3: 最后执行")
defer fmt.Println("2: 第二执行")
fmt.Println("1: 先执行")
// 输出顺序:1 → 2 → 3
}
package main
import (
"fmt"
"os"
)
// defer 最常见用途:确保资源释放
func readFile(path string) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // 无论后续如何,函数返回前必定关闭文件
buf := make([]byte, 64)
n, err := f.Read(buf)
if err != nil {
return err
}
fmt.Printf("读取了 %d 字节\n", n)
return nil
}
func main() {
// 创建测试文件
os.WriteFile("/tmp/go_test.txt", []byte("hello go"), 0644)
readFile("/tmp/go_test.txt")
}
函数作为值与闭包
package main
import "fmt"
// 函数类型
type MathFunc func(int, int) int
func apply(f MathFunc, a, b int) int {
return f(a, b)
}
// 闭包:函数捕获外部变量
func makeCounter() func() int {
count := 0
return func() int {
count++
return count
}
}
func main() {
add := func(a, b int) int { return a + b }
fmt.Println(apply(add, 3, 4)) // 7
counter := makeCounter()
fmt.Println(counter()) // 1
fmt.Println(counter()) // 2
fmt.Println(counter()) // 3
}
流程控制
if
package main
import "fmt"
func classify(score int) string {
// if 的初始化语句:变量作用域限定在 if 块内
if grade := score / 10; grade == 10 || grade == 9 {
return "A"
} else if grade >= 8 {
return "B"
} else if grade >= 6 {
return "C"
} else {
return "F"
}
}
func main() {
fmt.Println(classify(95)) // A
fmt.Println(classify(72)) // C
}
for(Go 唯一的循环语句)
package main
import "fmt"
func main() {
// 经典三段式(类 C)
for i := 0; i < 5; i++ {
fmt.Print(i, " ") // 0 1 2 3 4
}
fmt.Println()
// 只有条件(类 while)
n := 1
for n < 100 {
n *= 2
}
fmt.Println(n) // 128
// 无限循环
count := 0
for {
count++
if count >= 3 {
break
}
}
fmt.Println(count) // 3
// range 遍历(1.22+ 支持 range over integer)
for i := range 5 {
fmt.Print(i, " ") // 0 1 2 3 4
}
fmt.Println()
// range 遍历 slice
fruits := []string{"apple", "banana", "cherry"}
for i, v := range fruits {
fmt.Printf("%d: %s\n", i, v)
}
// range 遍历 map
m := map[string]int{"a": 1, "b": 2}
for k, v := range m {
fmt.Printf("%s=%d\n", k, v)
}
// range 遍历 string(按 rune)
for i, r := range "Hello, 世界" {
fmt.Printf("%d: %c\n", i, r)
}
}
switch
package main
import (
"fmt"
"runtime"
)
func main() {
// 基本 switch(无需 break,默认不穿透)
day := 3
switch day {
case 1, 7:
fmt.Println("周末")
case 2, 3, 4, 5, 6:
fmt.Println("工作日")
default:
fmt.Println("无效")
}
// 无条件 switch(等价于 if-else if 链)
score := 85
switch {
case score >= 90:
fmt.Println("A")
case score >= 80:
fmt.Println("B") // 输出 B
default:
fmt.Println("C")
}
// fallthrough:显式穿透到下一个 case
switch runtime.GOOS {
case "darwin":
fmt.Println("macOS")
fallthrough
case "linux":
fmt.Println("类 Unix 系统")
}
}
复合类型
array(固定长度)
package main
import "fmt"
func main() {
// 数组长度是类型的一部分,[3]int 和 [4]int 是不同类型
var a [3]int
b := [3]int{1, 2, 3}
c := [...]int{4, 5, 6, 7} // 编译器推断长度
fmt.Println(a) // [0 0 0]
fmt.Println(b) // [1 2 3]
fmt.Println(len(c)) // 4
// 数组是值类型,赋值会复制
d := b
d[0] = 99
fmt.Println(b[0], d[0]) // 1 99(互不影响)
}
slice(动态数组,最常用)
package main
import "fmt"
func main() {
// 创建 slice
s1 := []int{1, 2, 3}
s2 := make([]int, 3) // len=3, cap=3
s3 := make([]int, 3, 10) // len=3, cap=10
// 切片操作(左闭右开)
s := []int{0, 1, 2, 3, 4, 5}
fmt.Println(s[1:4]) // [1 2 3]
fmt.Println(s[:3]) // [0 1 2]
fmt.Println(s[3:]) // [3 4 5]
// append:超出 cap 时自动扩容(约 2 倍)
s1 = append(s1, 4, 5)
s1 = append(s1, []int{6, 7}...)
fmt.Println(s1) // [1 2 3 4 5 6 7]
// copy:深拷贝
dst := make([]int, len(s1))
n := copy(dst, s1)
fmt.Println(dst, n) // [1 2 3 4 5 6 7] 7
// slice 是引用类型,共享底层数组
a := []int{1, 2, 3}
b := a[:]
b[0] = 99
fmt.Println(a[0]) // 99(a 也被修改了)
fmt.Println(s2, s3)
}
map
package main
import "fmt"
func main() {
// 创建 map
m1 := map[string]int{"a": 1, "b": 2}
m2 := make(map[string]int) // 空 map,推荐用 make
// 增改
m2["key"] = 100
m1["c"] = 3
// 查询(comma ok 惯用法)
val, ok := m1["a"]
fmt.Println(val, ok) // 1 true
val, ok = m1["z"]
fmt.Println(val, ok) // 0 false(不存在时返回零值)
// 删除
delete(m1, "a")
// 遍历(顺序不固定)
for k, v := range m1 {
fmt.Printf("%s: %d\n", k, v)
}
fmt.Println(len(m1))
}
struct
package main
import "fmt"
type Person struct {
Name string
Age int
Email string
}
// 方法(见下一章节)
func (p Person) String() string {
return fmt.Sprintf("%s(%d)", p.Name, p.Age)
}
// 嵌套与组合(Go 的"继承"方式)
type Employee struct {
Person // 嵌入(匿名字段),提升 Person 的字段和方法
Company string
Salary float64
}
func main() {
// 字面量初始化(推荐按字段名)
p := Person{Name: "Alice", Age: 30, Email: "alice@example.com"}
fmt.Println(p) // {Alice 30 alice@example.com}
fmt.Println(p.String()) // Alice(30)
// 指针
pp := &Person{Name: "Bob", Age: 25}
pp.Age = 26 // 自动解引用,等价于 (*pp).Age = 26
fmt.Println(pp.Age) // 26
// 嵌入:可直接访问 Person 的字段
e := Employee{
Person: Person{Name: "Charlie", Age: 35},
Company: "ACME",
Salary: 50000,
}
fmt.Println(e.Name, e.Company) // Charlie ACME
fmt.Println(e.String()) // Charlie(35)(提升的方法)
// 匿名结构体(一次性使用)
point := struct {
X, Y int
}{X: 1, Y: 2}
fmt.Println(point) // {1 2}
}
指针
package main
import "fmt"
func increment(n *int) {
*n++ // 解引用并修改
}
func newInt(v int) *int {
// Go 允许返回局部变量的指针,编译器自动将其分配到堆上
return &v
}
func main() {
x := 42
p := &x // p 是指向 x 的指针,类型为 *int
fmt.Println(x) // 42
fmt.Println(p) // 0xc0000...(内存地址)
fmt.Println(*p) // 42(解引用)
*p = 100
fmt.Println(x) // 100(x 被修改)
increment(&x)
fmt.Println(x) // 101
// new:分配零值内存,返回指针
q := new(int) // *int,值为 0
*q = 99
fmt.Println(*q) // 99
ptr := newInt(10)
fmt.Println(*ptr) // 10
// Go 没有指针运算(不能 p++),比 C 更安全
}
方法与接口
方法
package main
import (
"fmt"
"math"
)
type Circle struct {
Radius float64
}
type Rectangle struct {
Width, Height float64
}
// 值接收者:方法内操作的是副本,不修改原值
func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}
// 指针接收者:可修改原值,大结构体时避免复制开销(推荐统一用指针接收者)
func (c *Circle) Scale(factor float64) {
c.Radius *= factor
}
func (r Rectangle) Area() float64 {
return r.Width * r.Height
}
func main() {
c := Circle{Radius: 5}
fmt.Printf("面积: %.2f\n", c.Area()) // 78.54
c.Scale(2) // Go 自动取地址:(&c).Scale(2)
fmt.Printf("缩放后半径: %.1f\n", c.Radius) // 10.0
r := Rectangle{Width: 3, Height: 4}
fmt.Printf("面积: %.2f\n", r.Area()) // 12.00
}
接口
package main
import (
"fmt"
"math"
)
// 接口:定义行为契约,隐式实现(无需 implements 关键字)
type Shape interface {
Area() float64
Perimeter() float64
}
type Circle struct{ Radius float64 }
type Rectangle struct{ Width, Height float64 }
func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius }
func (c Circle) Perimeter() float64 { return 2 * math.Pi * c.Radius }
func (r Rectangle) Area() float64 { return r.Width * r.Height }
func (r Rectangle) Perimeter() float64 { return 2 * (r.Width + r.Height) }
func printShape(s Shape) {
fmt.Printf("面积=%.2f 周长=%.2f\n", s.Area(), s.Perimeter())
}
func main() {
shapes := []Shape{
Circle{Radius: 5},
Rectangle{Width: 3, Height: 4},
}
for _, s := range shapes {
printShape(s)
}
}
类型断言与类型 switch
package main
import "fmt"
func describe(i interface{}) {
// 类型 switch
switch v := i.(type) {
case int:
fmt.Printf("int: %d\n", v)
case string:
fmt.Printf("string: %q\n", v)
case bool:
fmt.Printf("bool: %v\n", v)
default:
fmt.Printf("未知类型: %T\n", v)
}
}
func main() {
describe(42)
describe("hello")
describe(true)
describe(3.14)
// 单次类型断言
var i interface{} = "world"
s, ok := i.(string)
fmt.Println(s, ok) // world true
n, ok := i.(int)
fmt.Println(n, ok) // 0 false(断言失败,返回零值)
}
错误处理
error 接口
package main
import (
"errors"
"fmt"
)
// error 是内置接口:type error interface { Error() string }
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("除数不能为零")
}
return a / b, nil
}
// fmt.Errorf 支持格式化,%w 包裹原始错误(用于 errors.Is / errors.As)
func readConfig(path string) error {
if path == "" {
return fmt.Errorf("readConfig: %w", errors.New("路径不能为空"))
}
return nil
}
func main() {
if result, err := divide(10, 3); err != nil {
fmt.Println("错误:", err)
} else {
fmt.Printf("%.4f\n", result) // 3.3333
}
if _, err := divide(1, 0); err != nil {
fmt.Println("错误:", err) // 错误: 除数不能为零
}
err := readConfig("")
fmt.Println(err) // readConfig: 路径不能为空
}
自定义错误类型
package main
import (
"errors"
"fmt"
)
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("[%s] %s", e.Field, e.Message)
}
func validate(email string) error {
if email == "" {
return &ValidationError{Field: "email", Message: "不能为空"}
}
return nil
}
func main() {
err := validate("")
if err != nil {
fmt.Println(err) // [email] 不能为空
// errors.As:提取特定类型的错误
var ve *ValidationError
if errors.As(err, &ve) {
fmt.Println("字段:", ve.Field) // 字段: email
}
}
}
panic 与 recover
package main
import "fmt"
// recover 必须在 defer 中调用才有效
func safeDiv(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("捕获 panic: %v", r)
}
}()
return a / b, nil // b==0 时触发 panic: runtime error: integer divide by zero
}
func main() {
result, err := safeDiv(10, 2)
fmt.Println(result, err) // 5 <nil>
result, err = safeDiv(10, 0)
fmt.Println(result, err) // 0 捕获 panic: runtime error: integer divide by zero
}
原则:Go 中用
error处理预期错误,panic只用于不可恢复的程序错误(如数组越界、空指针)。库代码中不应将 panic 暴露给调用方。
并发
goroutine
package main
import (
"fmt"
"sync"
"time"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Printf("worker %d 开始\n", id)
time.Sleep(time.Millisecond * 100)
fmt.Printf("worker %d 结束\n", id)
}
func main() {
var wg sync.WaitGroup
// 启动 5 个 goroutine 并发执行
for i := 1; i <= 5; i++ {
wg.Add(1)
go worker(i, &wg)
}
wg.Wait() // 等待所有 goroutine 完成
fmt.Println("所有 worker 完成")
}
channel
package main
import "fmt"
func sum(nums []int, ch chan int) {
total := 0
for _, n := range nums {
total += n
}
ch <- total // 发送结果到 channel
}
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
ch := make(chan int) // 无缓冲 channel
go sum(nums[:5], ch)
go sum(nums[5:], ch)
a, b := <-ch, <-ch // 接收两个结果
fmt.Println(a, b, a+b) // 15 40 55(或 40 15 55,顺序不定)
// 带缓冲 channel:发送方不阻塞,直到缓冲区满
buffered := make(chan int, 3)
buffered <- 1
buffered <- 2
buffered <- 3
fmt.Println(<-buffered) // 1
// range channel:直到 channel 关闭
jobs := make(chan int, 5)
for i := 1; i <= 5; i++ {
jobs <- i
}
close(jobs)
for j := range jobs {
fmt.Print(j, " ") // 1 2 3 4 5
}
fmt.Println()
}
select
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() {
time.Sleep(50 * time.Millisecond)
ch1 <- "one"
}()
go func() {
time.Sleep(30 * time.Millisecond)
ch2 <- "two"
}()
// select:等待多个 channel,哪个先就绪就处理哪个
for i := 0; i < 2; i++ {
select {
case msg := <-ch1:
fmt.Println("收到 ch1:", msg)
case msg := <-ch2:
fmt.Println("收到 ch2:", msg)
}
}
// 带超时的 select
ch := make(chan int)
select {
case v := <-ch:
fmt.Println("收到:", v)
case <-time.After(100 * time.Millisecond):
fmt.Println("超时") // 输出:超时
}
}
sync 常用原语
package main
import (
"fmt"
"sync"
)
func main() {
// Mutex:互斥锁,保护共享数据
var mu sync.Mutex
counter := 0
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
counter++
mu.Unlock()
}()
}
wg.Wait()
fmt.Println("counter:", counter) // 1000
// Once:确保某操作只执行一次(如单例初始化)
var once sync.Once
for i := 0; i < 3; i++ {
once.Do(func() {
fmt.Println("只执行一次")
})
}
}
包与模块
package 规则
// 每个文件第一行声明所属包
package main // 可执行程序的入口包,必须有 main 函数
// 包名通常与目录名一致,小写,简短
// 导出标识符:首字母大写(Public)
// 未导出标识符:首字母小写(package private)
go mod 模块管理
# 初始化模块
go mod init github.com/yourname/myproject
# 添加依赖(自动更新 go.mod 和 go.sum)
go get github.com/gin-gonic/gin@v1.9.1
# 整理依赖(删除未使用,添加缺失)
go mod tidy
# 查看依赖图
go mod graph
# 下载所有依赖到本地缓存
go mod download
# vendor 模式(将依赖复制到项目 vendor 目录)
go mod vendor
go build -mod=vendor ./...
常用标准库速览
package main
import (
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
"strings"
"time"
)
func main() {
// strings:字符串处理
fmt.Println(strings.Contains("hello world", "world")) // true
fmt.Println(strings.Split("a,b,c", ",")) // [a b c]
fmt.Println(strings.Join([]string{"x", "y"}, "-")) // x-y
fmt.Println(strings.TrimSpace(" hi ")) // hi
fmt.Println(strings.ToUpper("hello")) // HELLO
fmt.Println(strings.ReplaceAll("aabbcc", "b", "X")) // aaXXcc
// fmt:格式化
s := fmt.Sprintf("name=%s age=%d", "Alice", 30)
fmt.Println(s) // name=Alice age=30
// time:时间处理
now := time.Now()
fmt.Println(now.Format("2006-01-02 15:04:05")) // Go 的参考时间是固定的
tomorrow := now.Add(24 * time.Hour)
fmt.Println(tomorrow.Format("2006-01-02"))
// os:操作系统接口
fmt.Println(os.Getenv("HOME"))
os.WriteFile("/tmp/go_demo.txt", []byte("hello"), 0644)
data, _ := os.ReadFile("/tmp/go_demo.txt")
fmt.Println(string(data)) // hello
// filepath:跨平台路径操作
p := filepath.Join("/tmp", "dir", "file.txt")
fmt.Println(p) // /tmp/dir/file.txt
fmt.Println(filepath.Base(p)) // file.txt
fmt.Println(filepath.Dir(p)) // /tmp/dir
fmt.Println(filepath.Ext(p)) // .txt
// encoding/json:JSON 序列化
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
}
person := Person{Name: "Alice", Age: 30}
b, _ := json.Marshal(person)
fmt.Println(string(b)) // {"name":"Alice","age":30}
var p2 Person
json.Unmarshal(b, &p2)
fmt.Println(p2.Name, p2.Age) // Alice 30
// net/http:HTTP 客户端
resp, err := http.Get("https://httpbin.org/get")
if err == nil {
fmt.Println("状态码:", resp.StatusCode)
resp.Body.Close()
}
}
快速参考卡
基本类型速查
| 类型 | 位宽 | 范围 / 说明 | 零值 |
|---|---|---|---|
bool | — | true / false | false |
int | 平台相关(32/64) | 有符号整数 | 0 |
int8 | 8 bit | -128 ~ 127 | 0 |
int16 | 16 bit | -32768 ~ 32767 | 0 |
int32 / rune | 32 bit | Unicode 码点 | 0 |
int64 | 64 bit | 大整数 | 0 |
uint8 / byte | 8 bit | 0 ~ 255 | 0 |
float32 | 32 bit | 单精度浮点 | 0 |
float64 | 64 bit | 双精度浮点(推荐) | 0 |
string | — | UTF-8 不可变字节序列 | "" |
error | — | 内置接口 | nil |
内置函数速查
| 函数 | 说明 |
|---|---|
len(v) | 返回 string/array/slice/map/channel 的长度 |
cap(v) | 返回 slice/channel 的容量 |
make(T, args) | 创建 slice、map、channel(返回引用) |
new(T) | 分配零值内存,返回 *T |
append(s, v...) | 向 slice 追加元素 |
copy(dst, src) | 复制 slice,返回复制的元素数 |
delete(m, k) | 删除 map 中的键 |
close(ch) | 关闭 channel |
panic(v) | 触发 panic |
recover() | 在 defer 中捕获 panic |
print / println | 内置输出(调试用,推荐用 fmt) |
常用符号速查
| 符号 | 含义 |
|---|---|
:= | 短变量声明(仅函数内) |
&v | 取变量地址,返回指针 |
*p | 解引用指针 |
<-ch | 从 channel 接收 |
ch <- | 向 channel 发送 |
... | 可变参数 / 展开 slice |
_ | 空白标识符,忽略返回值 |
参考资料
评论 (0)