相关信息
golang基础学习
context 的核心用途是控制请求链路的生命周期,比如取消、超时和传递少量请求级元数据。业务数据应该通过明确的函数参数传递,而不是放到 context.Value 里。否则会带来类型不安全、依赖隐式、可读性差和滥用成全局 Map 的问题。Context 里可以放 trace id、request id 这类跨函数、跨服务的元信息,但不应该放订单对象、用户实体这类核心业务数据
js1. 编译期(build)
2. 生成可执行文件
3. 运行时启动(runtime start)
4. 初始化 package 级别变量
5. 执行 init()
6. 执行 main.main()
js1. 语法检查
2. 类型检查
3. 依赖分析
4. 变量初始化代码生成(决定怎么初始化、按什么顺序初始化)
5. init 调用链生成
6. main 入口标记
golangvar f float64 = 3.1
i := int(f) // 3
jss := "你好"
r := []rune(s)
fmt.Println(len(s)) // 6
fmt.Println(len(r)) // 2
golangtype Reader interface {
Read([]byte)
}
type ReadWriter interface {
Read([]byte)
Write([]byte)
}
var rw ReadWriter
var r Reader = rw
golangfunc worker(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("worker exit")
return
default:
fmt.Println("working...")
time.Sleep(time.Second)
}
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
go worker(ctx)
time.Sleep(3 * time.Second)
cancel() // 通知退出
time.Sleep(time.Second)
}
| 类型 | 是否支持 cap | 返回值含义 |
|---|---|---|
| 数组(Array) | ✅ | 数组长度 |
| 数组指针(Pointer to Array) | ✅ | 指向数组的长度 |
| 切片(Slice) | ✅ | 切片容量 |
| 通道(Channel) | ✅ | 通道缓冲区容量 |
一句话总结:new是初始化为对应类型的零值;make初始化零值的同时,也初始化分配结构,比如在设置长度、容量的时候
数组是可以通过下标定义的
jsarray := [...]int{1,2,3,9:34} 表示array[9]==34 则len(array)就是10
js
import (
"fmt"
"unicode/utf8"
)
func main() {
var str = "hello 世界"
//golang中string底层是通过byte数组实现的
// 直接求len 实际是在按字节长度计算 所以一个汉字占3个字节算了3个长度
fmt.Println("len(str):", len(str))
//以下两种都可以得到str的字符串长度
//golang中的unicode/utf8包提供了用utf-8获取长度的方法
fmt.Println("RuneCountInString:", utf8.RuneCountInString(str))
//通过rune类型处理unicode字符
fmt.Println("rune:", len([]rune(str)))
}
// 结果为 12 8 8
fmt.Println(string([]rune(str)[7:])) //就能取出‘界’
golangtype hmap struct {
count int
B uint8
buckets unsafe.Pointer
oldbuckets unsafe.Pointer
...
}
nil 可以用作 interface、function、pointer、map、slice 和 channel 的“空值”
但是如果不特别指定的话,Go 语言不能识别类型
| 场景 | 描述 |
|---|---|
| 文件操作 | defer file.Close() 避免忘记关闭文件 |
| 锁操作 | defer mu.Unlock() 确保释放锁 |
| 数据库事务 | defer tx.Rollback() 或 Commit() |
| 捕获异常 | 搭配 recover() 使用来捕获 panic |
golangfunc test() {
defer fmt.Println("A")
defer fmt.Println("B")
defer fmt.Println("C")
}
执行结果是:
golangC B A
gofor i := 0; i < 3; i++ {
defer fmt.Println(i)
}
// 输出:2 2 2(不是 2 1 0)
gofor i := 0; i < 3; i++ {
v := i
defer fmt.Println(v)
}
// 输出:2 1 0
重要:每个goroutine都需要独立的recover机制,否则panic会导致整个程序崩溃。
gofunc safeGoRoutine() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Goroutine recovered:", r)
}
}()
// goroutine的业务逻辑
panic("goroutine panic")
}
func main() {
go safeGoRoutine()
time.Sleep(time.Second)
}
jstype WorkerManager struct {
//用来监控Worker是否已经死亡的缓冲Channel
workerChan chan *worker
// 一共要监控的worker数量
nWorkers int
}
//创建一个WorkerManager对象
func NewWorkerManager(nworkers int) *WorkerManager {
return &WorkerManager{
nWorkers:nworkers,
workerChan: make(chan *worker, nworkers),
}
}
//启动worker池,并为每个Worker分配一个ID,让每个Worker进行工作
func (wm *WorkerManager)StartWorkerPool() {
//开启一定数量的Worker
for i := 0; i < wm.nWorkers; i++ {
i := i
wk := &worker{id: i}
go wk.work(wm.workerChan)
}
//启动保活监控
wm.KeepLiveWorkers()
}
//保活监控workers
func (wm *WorkerManager) KeepLiveWorkers() {
//如果有worker已经死亡 workChan会得到具体死亡的worker然后 打出异常,然后重启
for wk := range wm.workerChan {
// log the error
fmt.Printf("Worker %d stopped with err: [%v] \n", wk.id, wk.err)
// reset err
wk.err = nil
// 当前这个wk已经死亡了,需要重新启动他的业务
go wk.work(wm.workerChan)
}
}
go ①可以用==比较
②不可以通过下标的方式改变某个字符,字符串是只读的
③不能和nil比较
jsvar et struct{}
et := struct{}{}
type ets struct {} / et := ets{} / var et ets
本文作者:曹子昂
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!