Golang随笔

结构体是Todo,Todo{}代表空结构体

新添加依赖后执行 go mod tidy整理依赖

匿名变量不会分配内存,所以匿名变量之间不存在重复声明。

单引号表示字符, 双引号表示字符串,反引号表示多行字符串

通过在 const 后跟一对圆括号定义一组常量的方式来实现枚举

type-switch用于判断某个 interface 变量中实际存储的变量类型

接口类型断言x.(T),且要求成员顺序一样;

json.unmarshal时数值型的 json 统一被解析为 float64;

Golang随笔_第1张图片

switch中默认每个case都会有隐藏的break,如果想去掉break可使用fallthrough;

go的i++值是一条语句,不能赋值,且只有i++没有++i。

unsafe.Sizeof是在编译期求值,返回的是类型数据结构的大小而不是其指向内存的大小。

var str string = "hello"
var str2 string

fmt.Println(unsafe.SizeOf(str), unsafe.SizeOf(str2))
string类型不是直接存的数据,而是一个结构体,用指针指向实际数据地址,
在64位机器。ptr和int结构都是占用8字节,所以两个打印出来都是字节

make([]string, 1, 2),len=1,cap=2;

make([]string, 2),len=2,cap=2

%p是指针的占位符;%+v是附带打印结构的key

	// 比较是否是指针
	m := make(map[string]string, 4)
	fmt.Println(reflect.DeepEqual(reflect.Ptr, reflect.ValueOf(&m).Kind()))

将函数作为参数变量或返回值的情况称为function value。function value本质上是一个指针,指向runtime.funcval结构体,这个结构体里只有一个地址,即函数指令的入口地址。闭包其实就是有捕获列表的funcval结构体,funcval加上偏移量可以找到每个捕获的变量。


	// 循环每秒执行一次
	for range time.Tick(time.Second){
		fmt.Println("hah")
	}

序列化:omitempty,如果是零值则忽略序列化该字段
反序列化:没有的字段会赋予零值

提示gc释放堆内存:如使用new在heap上开辟空间,使用结束后把指针置为nil。

结构体和数组作为复合类型,其零值以及能否比较、初始化、都是其内部的元素决定的,且复合类型占用连续的内存空间。


不能返回局部变量的地址,因为栈帧会被回收。

main goroutine退出后(相当于进程结束),其他的工作goroutine也会随之自动退出。

recover不能跨协程,会从panic点退出当前函数后继续执行。

`json:",inline"`  忽略这一层级的字段,直接调用下一层级,减少重复定义。应该和直接不写反引号效果一样。

内联是一种编译器优化,用于将简短函数的调用替换为函数体本身,可以消除函数调用本身的开销,也使得编译器能更高效地执行其他的优化策略。注释//go:noinline会禁止Go编译器对该函数进行内联。

go tool compile  -m main.go可以查看是否内联,内存是否分配到了堆上。

空结构体和零长数组(两个复合类型)都仅仅是一个占位符,不占用空间,这里编译器进行了优化,如果结构体或数组的unsafe.sizeof=0则直接返回zerobase。

runtime.KeepAlive 能保证变量不被 GC 所回收。

超时控制:请求时间过长用户侧可能已经离开页面,但是服务端还在消耗资源得到的结果没有意义;

close(channel)只是用来告诉接受者没有东西要发送了,并且channel和文件描述符不一样,只是个对象而已可以自己gc掉,并不是必须close关闭的;

单引号表示byte类型或rune类型,双引号表示字符串,反引号表示多行字符串;

for range会首先计算切片的长度,如果长度不满足就不进入循环;

接口到普通类型的转换用-接口类型断言;普通类型到普通类型的转换用-类型转换;只要有部分字段对应-序列化和反序列化;

前端(VO)<-->controller(DTO)<-->service(BO)<-->dao(PO)<-->数据库(DAO)
VO:一般用于前端展示用
DTO:用于数据传递(接口入参和接口返回值都可以)

10、singleflight

singleflight对共享资源的访问做限制,singleflight可以将相同的并发请求合并成一个请求,进而减少对下层服务的压力,通常用于解决缓存击穿的问题

11、RPC

RPC主要是基于TCP/IP协议的,而HTTP服务主要是基于HTTP协议的,从效率来看,RPC要更胜一筹,常见的RPC框架有谷歌的gRPC和阿里的Dubbo。

12、状态码

502:A访问B,请求被B接收了,但B未正常返回(B业务逻辑超时或B突然宕机无法返回等),这时候A会得到502状态码;
503:A访问B,B没有可接受流量的实例,则A会得到503状态码;
504:A访问B,请求被B接收了,A服务自身超时,但B会继续执行直到结束,这时候A会得到状态码504;

connect refused     可能是端口没有监听,也可能是自身应用有问题。

13、golang的panic信息

goroutine的跟踪信息中,Update函数实际有 3 个参数,但是 panic 时显示它携带超过 10 个参数,这是因为panic时显示的是域,且Update函数的返回值也会被添加到参数列表的末尾,比如:
字符串有两个域 (一个指向字符串数据的指针和一个长度);
切片有三个域 (一个指向底层数组的指针,一个长度,一个容量);
接口有两个域 (一个指向类型的指针和一个指向值的指针);

14、占位符

%v 默认格式的通用占位符,通常也是错误信息的占位符,
%+v 打印结构体时,会添加字段名
%s 字符串
%d 十进制整型
%f 有小数点的浮点数
%t 布尔值
%p 指针

15、LRU最近最少使用算法

LRU ,Least recently used,最近最少使用算法在缓存写满的时候,会根据所有数据的访问记录,淘汰掉最近最少被使用到的数据。也就是说该算法认为,最近被访问过的数据,在将来被访问的几率最大。

16、golang的继承

在 deployment 的定义中 type meta 和 object meta 类型并没有名称的定义,而是直接写的类型。在 go 语言中,这种特性就相当于是java 语言的继承。所以在 kubernetes 世界里所有的 resource 定义之中,通过继承的方式来继承了 type meta 和 object meta 两种类型

17、httpClient的单例

普通的httpClient相当于浏览器,如果单例模式只使用一个client在并发时候会有多线程问题;但是okHttpClient是单例的,也是通过synchronized保证线程安全。

18、压缩解压

压缩.tar     tar -cvf xxx.tar xxx
解压.tar     tar -xvf xxx.tar
压缩.tar.gz     tar -zcvf xxx.tar.gz xxx
解压.tar.gz     tar -zxvf xxx.tar.gz

19、pprof和trace

pprof 可以看 CPU、内存、协程等信息在特定流量进来时系统调用的各部分耗时情况,一般锁定火焰图的平顶山逻辑,看优化可能性:异步化,改逻辑,加 cache 等;
trace 可以查看 runtime 的情况,比如可以查看协程调度信息等;

右侧的runtime 部分一般先忽略,而剩下的火焰图中圈出来的大平顶山都是可以优化的地方

Golang随笔_第2张图片

Golang随笔_第3张图片

20、for循环的坑

(1)对循环变量取地址

var all []*Item
for _, item := range items {
 item := item
 all = append(all, &item)
}

(2)闭包,没有立即执行

var prints []func()
for _, v := range []int{1, 2, 3} {
 v:=v
 prints = append(prints, func() { fmt.Println(v) })
}
for _, print := range prints {
 print()
}

(3)协程

for _, v := range []int{1, 2, 3} {
 v:=v
 go func(){
  fmt.println(v)
 }
}

21、ambiguous import

Go包ambiguous import问题一般是由于引用包的多个路径里有go.mod文件导致,这种情况一般是gopath过渡到gomod的问题。这种情况可以通过以下方式解决:
 

go get cloud.google.com/go/compute/metadata
go mod tidy

22、go module伪版本

go mod 伪版本 伪版本主要有两种。

一种是v0.0.0开头的:

golang.org/x/lint v0.0.0-20200302205851-738671d3881b

这种是依赖模块的代码仓库上不存在任何标签,所以go get 默认拉取的是主干分支最新一次commit对应版本的代码,并且在go.mod文件里为模块分配格式为 v0.0.0-主干分支最新一次commit的时间-commit哈希 这样的一个虚拟版本。

另一种是非 v0.0.0 开头的伪版本:

code.xxx.com/libs/xyz v1.0.10-0.20220805095508-6c1f3628ef7a

一般是作为依赖包的项目本身代码仓库里有打标签发布版本,可是后续我们需要更新包,在测试阶段的时候在项目使用go get 模块名@CommitHash 获取还未正式发布的内容:

go get code.xxx.com/libs/xyz@6c1f3628ef7a

23、502、503、504状态码

502:A访问B,请求被B接收了,但B未正常返回(B业务逻辑超时或B突然宕机无法返回等),这时候A会得到502状态码;
503:A访问B,B没有可接受流量的实例,则A会得到503状态码;
504:A访问B,请求被B接收了,A服务自身超时,但B会继续执行直到结束,这时候A会得到状态码504;

你可能感兴趣的:(Golang笔记,Golang)