相关信息
golang基础学习
js1. 编译期(build)
2. 生成可执行文件
3. 运行时启动(runtime start)
4. 初始化 package
5. 执行 init()
6. 执行 main.main()
一般可以理解为main执行之前
js1️. var 变量初始化(初始化的真正执行)(全局变量,也就是package级别的变量)
2️. init()
3️. main()
js1. 语法检查
2. 类型检查
3. 依赖分析
4. 变量初始化代码生成(决定怎么初始化、按什么顺序初始化)
5. init 调用链生成
6. main 入口标记
go ①可以用==比较
②不可以通过下标的方式改变某个字符,字符串是只读的
③不能和nil比较
数组是可以通过下标定义的
jsarray := [...]int{1,2,3,9:34} 表示array[9]==34 则len(array)就是10
jsvar et struct{}
et := struct{}{}
type ets struct {} / et := ets{} / var et ets
数组、切片、通道
一句话总结:new是初始化为对应类型的零值;make初始化零值的同时,也初始化分配结构,比如在设置长度、容量的时候
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:])) //就能取出‘界’
一般我们给一个引用类对象中的引用类成员进行赋值,可能出现逃逸现象。可以理解为访问一个引用对象实际上底层就是通过一个指针来间接的访问了,但如果再访问里面的引用成员就会有第二次间接访问,这样操作这部分对象的话,极大可能会出现逃逸的现象。
对于引用类型的变量,我们不光要声明它,还要为它分配内容空间,否则我们的值放在哪里去呢
(https://www.caoziang.com/static/img/76c7a8bf10da15d974ced47f6aa346d2.image.webp)
jsgRPC 是一个基于 HTTP/2 和 Protobuf 的高性能 RPC 框架,
支持多语言和流式通信,
主要用于微服务之间的高性能调用。
相比 REST,它序列化效率更高、连接复用能力更强,
但可读性较差,
更适合内部服务通信。
简单的说就是在修改需求的时候,应该尽量通过扩展来实现变化,而不是通过修改已有代码来实现变化
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)
原因: defer 延迟执行,i 的值在循环结束时为 2,所有 defer 引用的是同一个 i 正确的写法
gofor i := 0; i < 3; i++ {
v := i
defer fmt.Println(v)
}
// 输出:2 1 0
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)
}
}
本文作者:曹子昂
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!