Golang 基础与实战笔记:从语法到微服务的全面指南
本文基于作者多年的 Go 语言开发经验,系统整理了 Go 语言的基础语法、核心特性、并发编程模型、常用框架和微服务开发等方面的知识,适合有一定编程基础、想快速掌握 Go 语言的开发者阅读。
一、Go 语言简介与环境搭建
1.1 Go 语言概述
Go 语言(又称 Golang)是 Google 于 2009 年推出的一种静态强类型、编译型语言。它的设计目标是:在不损失应用程序性能的情况下降低代码的复杂性。Go 语言专门针对多处理器系统应用程序的编程进行了优化,使用 Go 编译的程序可以媲美 C 或 C++ 代码的速度,而且更加安全、支持并行进程。
Go 语言被广泛应用于以下场景:
- Web 服务器和存储集群等巨型中央服务器的系统编程
- 高性能分布式系统开发
- 游戏服务端开发(天然支持海量并行)
- 云原生和容器化技术(Docker、Kubernetes 均用 Go 编写)
1.2 Go 版本管理
推荐使用 goup 工具来管理本地的 Go 版本,方便在不同版本间切换:
bash
# 安装 goup(Windows 平台)
# 从 https://github.com/owenthereal/goup/releases 下载最新版
# 初始化
goup init --skip-install --skip-prompt
# 安装指定版本(使用国内镜像)
GOUP_GO_HOST=golang.google.cn goup install 1.22.0
# 切换版本
goup default 1.22.0
# 验证
go version
1.3 第一个 Go 程序
go
package main
import "fmt"
func main() {
fmt.Println("Hello Golang")
}
程序结构说明:
| 组成部分 | 说明 |
|---|---|
package main |
包声明,main 包表示一个可独立执行的程序 |
import "fmt" |
引入 fmt 包,实现格式化 I/O |
func main() |
程序入口函数,每个可执行程序必须包含 |
fmt.Println(...) |
输出字符串到控制台,自动添加换行符 |
编译与运行:
bash
# 编译生成可执行文件
go build hello.go
# 直接运行(不生成可执行文件)
go run hello.go
可见性规则: 当标识符(常量、变量、类型、函数名、结构字段等)以大写字母开头时,可以被外部包的代码使用(类似 public);以小写字母开头则对包外不可见(类似 protected)。
二、基础语法
2.1 变量与常量
Go 语言提供三种变量声明方式:
go
// 方式一:指定类型,声明后若不赋值使用默认值(零值)
var a int
a = 10
// 方式二:根据值自行判定类型
var b = 10
// 方式三:短变量声明(只能在函数内使用,左侧变量不能已声明过)
c := 10
多变量声明:
go
var (
err error
result, score int64
)
常量与 iota:
go
const identifier [type] = value
// 枚举常量
const (
Unknown = 0
Female = 1
Male = 2
)
// iota:特殊常量,每次 const 出现时重置为 0
const (
a = iota // 0
b // 1
c // 2
)
_(下划线)是一个只写变量,常用于忽略函数返回值中不需要的部分:
go
_, b = 5, 7 // 值 5 被抛弃
2.2 数据类型
Go 语言按类别有以下几种数据类型:
基本类型:
| 类型 | 描述 |
|---|---|
bool |
布尔型,值只能是 true 或 false |
int/int8/int16/int32/int64 |
有符号整型 |
uint/uint8/uint16/uint32/uint64 |
无符号整型 |
float32/float64 |
浮点型 |
complex64/complex128 |
复数类型 |
byte |
类似 uint8 |
rune |
类似 int32,表示一个 Unicode 码点 |
string |
字符串,字节使用 UTF-8 编码 |
派生类型: 指针类型、数组类型、结构体类型(struct)、Channel 类型、函数类型、切片类型、接口类型(interface)、Map 类型。
类型转换:
go
// Go 不支持隐式类型转换,必须显式转换
var a = int(12.34) // a = 12
// 类型别名 vs 类型定义
type MyInt1 = int // 类型别名,MyInt1 和 int 完全相同
type MyInt2 int // 类型定义,创建了一种新类型
fmt.Printf("%T %T\n", MyInt1(1), MyInt2(1))
// 输出:int main.MyInt2
2.3 运算符与控制流
运算符: Go 语言的运算符基本和 C 语言相同,但有以下区别:
- 没有前置
++和后置++的区别,++只是语句而非表达式 - 关系运算符的结果是
bool型
条件语句:
go
// if-else
if a == b {
handle()
}
// switch
switch x {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
default:
fmt.Println("other")
}
select 语句: 类似于用于通信的 switch 语句,每个 case 必须是一个通信操作(channel 发送或接收):
go
select {
case msg := <-ch1:
fmt.Println("received", msg)
case ch2 <- msg:
fmt.Println("sent", msg)
default:
fmt.Println("no activity")
}
循环语句: Go 只有 for 循环,但可以模拟 while 和无限循环:
go
// 经典 for 循环
for i := 0; i < 10; i++ {
fmt.Printf("i = %d\n", i)
}
// 模拟 while
for a < b {
a++
}
// 无限循环
for {
// ...
}
// range 迭代
nums := []int{2, 3, 4}
for i, num := range nums {
fmt.Printf("index: %d, value: %d\n", i, num)
}
2.4 函数
go
// 基本函数定义
func function_name(parameter_list) return_types {
// 函数体
}
// 多返回值(Go 的特色功能)
func swap(a, b int) (int, int) {
return b, a
}
// 命名返回值
func divide(a, b int) (result int, err error) {
if b == 0 {
err = errors.New("division by zero")
return
}
result = a / b
return
}
defer 关键字: defer 用于在函数返回前执行某些操作,常用于资源释放。执行顺序为先进后出(栈):
go
func do() (ok bool) {
file, _ := os.Open("a.txt")
defer file.Close() // 函数返回前自动关闭文件
// doSomething
return ok
}
// defer 的执行顺序是逆序的
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
// 输出:4 3 2 1 0
2.5 结构体与方法
go
// 定义结构体
type Book struct {
Title string
Author string
Price float64
}
// 创建实例
b := Book{Title: "Go Programming", Author: "John", Price: 59.9}
// 方法定义(值接收者 vs 指针接收者)
func (m Book) GetValue() int {
return m.Price // 不能修改调用者的值
}
func (m *Book) SetValue(price float64) {
m.Price = price // 可以修改调用者的值
}
注意: 与 C 语言不同,Go 中指针类型的结构体访问成员变量也使用 . 操作符,而不是 ->。
三、核心数据结构深入
3.1 切片(Slice)
切片是 Go 中对数组的抽象,是"动态数组",长度不固定,可以追加元素。
go
// 创建切片
s := []int{1, 2, 3} // 直接初始化
s := make([]int, 5, 10) // make([]T, length, capacity)
s := arr[startIndex:endIndex] // 从数组切片
// append 追加元素
s = append(s, 4)
s = append(s, 5, 6, 7)
// copy 复制切片
dst := make([]int, len(s), cap(s)*2)
copy(dst, s)
// copy 也可以将 string 复制给 byte 切片
buf := make([]byte, 10)
copy(buf, "hello")
切片技巧:
go
// 允许对 nil 切片添加元素(但对 nil map 会 panic)
var s []int
s = append(s, 1) // 这是合法的
// 只循环不取值的高效写法
slice := make([]struct{}, 100)
for range slice {
// 执行 100 次
}
3.2 Map(集合/哈希表)
go
// 创建 Map
m := make(map[string]string)
m["key"] = "value"
// 遍历 Map
for k, v := range m {
fmt.Printf("%s -> %s\n", k, v)
}
// 删除元素
delete(m, "key")
// 判断 key 是否存在
value, ok := m["key"]
if ok {
fmt.Println("found:", value)
}
注意事项:
- 在创建 map 时可以指定容量,但不能像 slice 一样使用
cap()检测分配空间大小 - 对值为
nil的 map 添加元素会引发运行时 panic
3.3 Channel(通道)
Channel 是 Go 语言并发编程的核心,用于在 goroutine 之间安全地传递数据。
go
// 创建通道
ch := make(chan int, 10) // 带缓冲的通道,容量为 10
// 发送和接收
ch <- 42 // 发送
value := <-ch // 接收
// 关闭通道后,缓冲中的数据还可以读出
close(ch)
// 判断通道是否关闭
v, ok := <-ch
if !ok {
fmt.Println("channel closed")
}
// 使用 for + range 读取通道(通道关闭后自动退出循环)
for v := range ch {
fmt.Println(v)
}
Channel 使用技巧:
go
// 单向通道(通常作为函数参数)
func producer(ch chan<- int) { // 只写通道
ch <- 42
}
func consumer(ch <-chan int) { // 只读通道
v := <-ch
fmt.Println(v)
}
// len(ch) 返回已写入但未消费的元素个数
// cap(ch) 返回通道的容量
Channel 规则总结:
| 操作 | nil 通道 | 已关闭通道 | 正常通道 |
|---|---|---|---|
| 发送 | 永久阻塞 | panic | 阻塞或成功 |
| 接收 | 永久阻塞 | 返回零值 | 阻塞或成功 |
| 关闭 | panic | panic | 成功 |
3.4 内存对齐
Go 默认采用类似 C/C++ 的内存对齐机制。内存对齐的原因:
- 平台移植性: 不是所有硬件平台都能访问任意地址上的任意数据
- 性能提升: 对齐的内存只需一次访问即可完成读取,空间换时间
对齐原则: 一个结构体内的对齐系数取决于最大的成员字节数,但不超过平台系数(64 位平台为 8)。
go
type T struct {
a byte
b uint16 // unsafe.Sizeof(*new(T)) == 4
}
// 32 位下访问 int64 结构体成员的注意事项
type T1 struct {
a int32
_ int32 // 占位符,使结构体按 8 字节对齐
b int64
}
使用 unsafe.Alignof(v) 查看对齐系数,使用 unsafe.Sizeof(v) 查看实际占用大小。
四、并发编程
4.1 GMP 调度模型
GMP 是 Go 语言运行时的核心调度模型,理解它对编写高效并发程序至关重要:
- G(Goroutine): 用户态协程,轻量级线程
- M(Machine/Thread): 操作系统线程(内核态),最大 10000 个
- P(Processor): 逻辑处理器,最大 256 个(可通过
runtime.GOMAXPROCS设置)
调度流程:
- 每个 Go 程序有全局队列和每个 P 维护的本地队列
- Goroutine 创建时加入 P 的本地队列,满了后放入全局队列
- P 将本地队列的 G 放到 M 中运行,每个 G 有时间片
- 当 G 遇到阻塞任务时,P 会分离当前 M,创建新 M 执行队列中的 G
- P 先从本地队列找 G,没有则从全局队列找,再去其他 P 中"偷"
go
// 设置使用的 CPU 核心数
runtime.GOMAXPROCS(runtime.NumCPU())
// 让出时间片
runtime.Gosched()
4.2 Goroutine 与 Channel 实战
go
// 启动 goroutine
go func() {
fmt.Println("hello from goroutine")
}()
// 使用 channel 通信
func producer(ch chan<- int) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
func consumer(ch <-chan int, done chan<- bool) {
for v := range ch {
fmt.Println("received:", v)
}
done <- true
}
func main() {
ch := make(chan int, 5)
done := make(chan bool)
go producer(ch)
go consumer(ch, done)
<-done // 等待消费者完成
}
4.3 sync 同步工具
Go 的 sync 包提供了多种实用的同步工具:
go
// 1. Mutex - 普通互斥锁
var mu sync.Mutex
mu.Lock()
// 临界区
mu.Unlock()
// 2. RWMutex - 读写锁
var rw sync.RWMutex
rw.RLock() // 读锁,多个 goroutine 可同时持有
rw.RUnlock()
rw.Lock() // 写锁,独占
rw.Unlock()
// 3. Once - 只执行一次(常用于单例模式)
var once sync.Once
once.Do(func() {
// 初始化操作,只会执行一次
})
// 4. WaitGroup - 等待一组 goroutine 完成
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
// do work
}()
}
wg.Wait()
// 5. Map - 线程安全的 Map
var m sync.Map
m.Store("key", "value")
v, ok := m.Load("key")
// 6. Pool - 对象池
var pool = sync.Pool{
New: func() interface{} {
return new(MyObject)
},
}
obj := pool.Get().(*MyObject)
pool.Put(obj)
// 7. Cond - 条件变量
cond := sync.NewCond(&mu)
cond.Wait() // 等待信号
cond.Signal() // 唤醒一个等待者
cond.Broadcast() // 唤醒所有等待者
4.4 Atomic 原子操作
go
// 基本类型的原子操作
var counter int64
atomic.AddInt64(&counter, 1)
atomic.LoadInt64(&counter)
atomic.StoreInt64(&counter, 100)
// 任意类型的原子操作
var value atomic.Value
value.Store("hello")
v := value.Load().(string)
4.5 Context 上下文
Context 是处理慢请求时管理多个 goroutine 生命周期的重要手段:
go
// 创建可取消的 context
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// 创建超时 context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// 在 goroutine 中使用
go func(ctx context.Context) {
select {
case <-ctx.Done():
fmt.Println("cancelled:", ctx.Err())
case <-time.After(3 * time.Second):
fmt.Println("work done")
}
}(ctx)
通过派生方式生成子 context,父 context 调用 cancel 函数时,各子 context 都能收到信号。
五、包管理与依赖
5.1 Go Modules(推荐)
Go Module 是 Go 1.11 之后官方推荐的包管理方式,是 Go 最终的包管理工具。
bash
# 初始化模块
go mod init github.com/yourname/project
# 下载依赖
go mod tidy
# 指定版本下载
go get github.com/some/package@v2.0.0
# 设置国内代理
go env -w GOPROXY=https://goproxy.cn,direct
go env -w GOSUMDB=sum.golang.google.cn
go.mod 文件示例:
module github.com/yourname/project
go 1.22
require (
github.com/gin-gonic/gin v1.9.1
gorm.io/gorm v1.25.0
)
大版本约定: 当模块版本 >= v2.0.0 时,模块路径必须添加版本后缀:
module github.com/panicthis/modfile/v2
5.2 Vendor 模式
Vendor 模式将工程中所有第三方依赖打包进 vendor 目录,适合不能访问外网的生产环境:
bash
# Go Module 项目使用 vendor
go mod vendor # 创建 vendor 目录
go build -mod=vendor # 编译时指定使用 vendor
5.3 导入包的几种形式
go
import "github.com/zhouwy1994/library" // 正常导入
import lib "github.com/zhouwy1994/library" // 别名导入
import . "github.com/zhouwy1994/library" // 直接使用(不推荐)
import _ "github.com/zhouwy1994/library" // 仅执行 init()
下划线的三个用途:
import _--- 仅初始化包,不使用其中的方法file, _ := os.Open(...)--- 忽略返回值var _ Interface = &Struct{}--- 接口断言,确保结构体实现了接口
六、Protobuf 与 gRPC
6.1 Protobuf
Protobuf 是一种跨语言的数据序列化工具,支持 bool、int、double、float、string、bytes、map、repeated 等类型。
6.2 gRPC 四种服务接口
protobuf
syntax = "proto3";
service RouteGuide {
// 1. 简单 RPC(一问一答,最常用)
rpc GetFeature(Point) returns (Feature) {}
// 2. 服务器端流式 RPC
rpc ListFeatures(Rectangle) returns (stream Feature) {}
// 3. 客户端流式 RPC
rpc RecordRoute(stream Point) returns (RouteSummary) {}
// 4. 双向流式 RPC
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
编译与使用:
bash
# 编译 proto 文件
protoc -I proto/ proto/route_guide.proto \
--go_out=plugins=grpc:../routeguide
服务端实现:
go
type routeGuideServer struct{}
func (s *routeGuideServer) GetFeature(ctx context.Context, point *pb.Point) (*pb.Feature, error) {
// 实现业务逻辑
return &pb.Feature{}, nil
}
// 启动 gRPC 服务
lis, _ := net.Listen("tcp4", ":3456")
grpcServer := grpc.NewServer()
pb.RegisterRouteGuideServer(grpcServer, &routeGuideServer{})
grpcServer.Serve(lis)
客户端调用:
go
conn, _ := grpc.Dial("127.0.0.1:3456", grpc.WithInsecure())
client := pb.NewRouteGuideClient(conn)
feature, _ := client.GetFeature(context.Background(), &pb.Point{Latitude: 409146138})
七、HTTP 服务器与 Web 框架
7.1 Go 原生 HTTP 服务器
go
// 简单的文件服务器(仅需两行代码)
http.Handle("/", http.FileServer(http.Dir("./")))
http.ListenAndServe(":8888", nil)
核心概念:
- 处理器(Handler): 实现了
Handler接口的ServeHTTP方法 - 处理器函数: 签名为
func(ResponseWriter, *Request)的函数 - ServeMux: 多路复用器,负责 URL 路由分发
7.2 Web 框架对比与选型
| 框架 | 定位 | 特点 | 适用场景 |
|---|---|---|---|
| Echo | 轻量级 | 高性能、可扩展、极简 | 小型业务 |
| Gin | 中量级 | 高性能、中间件丰富、社区活跃 | 中型业务 |
| Beego | 重量级 | 完整 MVC、自带 ORM/Session | 大型业务 |
| Fiber | 轻量级 | 类 Express 风格、基于 fasthttp | 高性能 API |
7.3 Gin 框架实战
go
package main
import "github.com/gin-gonic/gin"
type Request struct {
Name string `form:"name" json:"name" binding:"required"`
Timestamp string `form:"timestamp" json:"timestamp" binding:"required"`
}
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "pong"})
})
r.POST("/submit", func(c *gin.Context) {
var req Request
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"status": "ok"})
})
r.Run(":8080")
}
Gin 的参数绑定(binding)标签: 支持丰富的验证规则,如 required、len=64、gt=10、oneof=red green、email、url 等。
7.4 中间件原理
中间件的本质是"处理器串联",通过层层包裹实现横切关注点:
go
// 计时中间件
func TimingMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next() // 调用下一个处理器
elapsed := time.Since(start)
fmt.Printf("Request took %v\n", elapsed)
}
}
八、日志框架
8.1 Zap(高性能,推荐)
go
func NewZapLogger(path, baseFile string, saveDays int, level string) *zap.SugaredLogger {
// 日志分割器
lumberJackLogger := &lumberjack.Logger{
Filename: fmt.Sprintf("%s/%s", path, baseFile),
MaxSize: 64, // MB
MaxBackups: saveDays, // 最大保留个数
MaxAge: saveDays, // 最大保留天数
Compress: false,
}
// 日志编码器
encoderConfig := zapcore.EncoderConfig{
TimeKey: "time",
LevelKey: "level",
CallerKey: "file",
FunctionKey: zapcore.OmitKey,
MessageKey: "msg",
StacktraceKey: "stacktrace",
LineEnding: zapcore.DefaultLineEnding,
EncodeLevel: zapcore.CapitalLevelEncoder,
EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
},
EncodeDuration: zapcore.MillisDurationEncoder,
EncodeCaller: zapcore.ShortCallerEncoder,
}
// 设置日志级别
atomicLevel := zap.NewAtomicLevel()
switch level {
case "debug":
atomicLevel.SetLevel(zap.DebugLevel)
case "release":
atomicLevel.SetLevel(zap.InfoLevel)
}
// 构建日志记录器
jsonEncoder := zapcore.NewJSONEncoder(encoderConfig)
writeSyncer := zapcore.NewMultiWriteSyncer(
zapcore.AddSync(os.Stdout),
zapcore.AddSync(lumberJackLogger),
)
core := zapcore.NewCore(jsonEncoder, writeSyncer, atomicLevel)
logger := zap.New(core, zap.AddCaller(), zap.Development())
return logger.Sugar()
}
8.2 Logrus(高度可定制化)
Logrus 通过 Hook 机制实现高度定制:
go
import "github.com/sirupsen/logrus"
log := logrus.New()
log.SetFormatter(&logrus.JSONFormatter{
TimestampFormat: "2006-01-02 15:04:05",
})
log.SetReportCaller(true)
log.Info("application started")
8.3 日志记录通用步骤
- 创建日志分割器(Hook),如
lumberjack、file-rotatelogs - 设置日志编码器格式(JSON/TEXT)、通用字段(time, level, file, line, msg)
- 设置日志等级(debug, info, warn, error)
- 将分割器和编码器绑定到日志记录器
- 封装日志接口(Info, Infof, InfoWithFields 等)
九、DLL/SO 调用(CGO 与 syscall)
Go 调用 C 库是所有语言中最方便的之一:
9.1 使用 syscall 调用 DLL
go
dllHandle, err := syscall.LoadLibrary("WaveApi.dll")
if err != nil {
log.Fatal(err)
}
defer syscall.FreeLibrary(dllHandle)
proc, err := syscall.GetProcAddress(dllHandle, "waveInInit")
if err != nil {
log.Fatal(err)
}
// 调用带回调的 DLL 函数
callback := syscall.NewCallback(func(data unsafe.Pointer, length int, user unsafe.Pointer) int {
// 处理回调数据
return 0
})
syscall.Syscall6(proc, 5,
uintptr(channels),
uintptr(samplesPerSec),
uintptr(bitPerSec),
callback,
uintptr(0), 0)
9.2 使用 CGO 直接调用 C 代码
go
/*
#include <stdio.h>
#include <stdlib.h>
char* hello() {
return "Hello from C!";
}
*/
import "C"
import "unsafe"
func main() {
// 调用 C 函数
cStr := C.hello()
goStr := C.GoString(cStr) // C 字符串转 Go 字符串
fmt.Println(goStr)
// Go 字符串转 C 字符串(需手动释放)
goStr := "Hello from Go"
cStr := C.CString(goStr)
defer C.free(unsafe.Pointer(cStr))
}
十、go-micro 微服务开发
10.1 Micro 与 go-micro 的关系
- go-micro 是一套编写微服务的框架,让编写微服务变得更加简单
- Micro 是一个完整的微服务生态,包含框架(go-micro)、运行时管理、网络共享等
Micro 自带的运行时服务替代了常用的中间件:
- api --- 替代 API 网关
- broker --- 替代 Kafka、RabbitMQ 等消息队列
- config --- 替代 Nacos、Etcd 等配置中心
- registry --- 替代 Nacos、Etcd 等注册中心
- store --- 替代 Redis、Memcache 等缓存
10.2 创建微服务
bash
# 使用脚手架创建项目
micro new helloworld
生成的目录结构:
.
├── main.go
├── handler/
│ └── hello.go
├── proto/
│ └── hello.proto
├── Dockerfile
├── Makefile
├── go.mod
└── micro.mu
注意事项: 使用 go-micro 时要注意版本匹配(v1/v2/v3/v4),protoc-gen-micro 工具也要使用对应版本编译。
10.3 常用第三方库清单
| 库名 | 用途 |
|---|---|
| GORM | 数据库 ORM 操作 |
| Gin | 高性能 Web 框架 |
| go-redis | Redis 客户端 |
| Viper | 配置文件读写(支持 JSON/TOML/YAML 等) |
| Swagger | API 文档自动生成 |
| go-simplejson | JSON 解析库 |
| goquery | HTML 解析(爬虫利器) |
| excelize | Excel 文件处理 |
| go-qrcode | 二维码生成 |
| pigo | 人脸检测(不依赖 OpenCV) |
| progressbar | 进度条显示 |
总结
Go 语言凭借其简洁的语法、强大的并发模型和丰富的生态,已成为后端开发的热门选择。本文涵盖了以下核心知识点:
- 基础语法: 变量、常量、数据类型、控制流、函数、结构体
- 核心数据结构: Slice、Map、Channel 的深入理解和使用技巧
- 内存对齐: 理解 Go 的内存布局和对齐规则
- 并发编程: GMP 调度模型、goroutine/channel/sync 包的实战使用
- 包管理: Go Modules 和 Vendor 模式的使用
- Web 开发: 原生 HTTP、Gin/Echo/Beego 框架对比与实战
- 日志框架: Zap 和 Logrus 的配置与使用
- 跨语言调用: CGO 和 syscall 调用 DLL/SO
- 微服务: go-micro 框架和 Protobuf/gRPC 的使用
Go 语言的学习曲线平缓,但要写出高效、优雅的 Go 代码需要深入理解其并发模型和设计哲学。希望本文能帮助你在 Go 语言的学习和实践中少走弯路。
原始笔记来源:
jdah/study on golang.gozyh/LearnGolang.gozyh/gomicro.go