-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Go 开发笔记 #21
Comments
使用github.com/go-sql-driver/mysql时, 无法Exec多条sql语句报错一般为编码1064, 指示为语法错误. 为降低sql注入的风险, multi statements默认为不支持. 向 |
nil判断迷思在 Go 语言中,当你将一个空指针(nil)赋值给一个接口类型的变量时,这个接口变量会被初始化为一个非 nil 的接口值。这是因为接口包含三个部分:类型信息、值信息和方法集。即使值信息是 nil,接口本身仍然包含类型信息和方法集,因此整个接口并不是 nil。 示例代码package main
import "fmt"
type MyStruct struct{}
func main() {
var ptr *MyStruct = nil
var iface interface{} = ptr
fmt.Println(iface == nil) // 输出 false
iface = nil
fmt.Println(iface == nil) // 输出 true
} 在赋值语句 var iface interface{} = ptr 执行后,即使 ptr 是 nil,iface 也会包含关于 ptr 类型的信息,即 *MyStruct 类型。 所以要判断接口类型是否为 nil 时,较为稳妥的方法是使用 reflect 获取值信息再进行判断。 示例代码package main
import (
"fmt"
"reflect"
)
type MyStruct struct{}
func main() {
var ptr *MyStruct = nil
var iface interface{} = ptr
fmt.Println(iface == nil) // 输出 false
v := reflect.ValueOf(iface)
fmt.Println(!v.IsValid() || v.IsNil()) // 输出 true
iface = nil
fmt.Println(iface == nil) // 输出 true
v = reflect.ValueOf(iface)
fmt.Println(!v.IsValid() || v.IsNil()) // 输出 true
} |
float 类型作为 map 的 keyfunc main() {
m := make(map[float64]int)
m[2.4] = 2
fmt.Printf("k: %v, v: %d\n", 2.4, m[2.4])
fmt.Printf("k: %v, v: %d\n", 2.400000000001, m[2.400000000001])
fmt.Printf("k: %v, v: %d\n", 2.4000000000000000000000001, m[2.4000000000000000000000001])
} output:
当用 float64 作为 key 的时候,先要将其转成 uint64 类型,再插入 key 中。 具体是通过 Float64frombits 函数完成: // Float64frombits returns the floating point number corresponding
// the IEEE 754 binary representation b.
func Float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) } func main() {
fmt.Println(math.Float64bits(2.4))
fmt.Println(math.Float64bits(2.400000000001))
fmt.Println(math.Float64bits(2.4000000000000000000000001))
} output:
2.4 和 2.4000000000000000000000001 经过 math.Float64bits() 函数转换后的结果是一样的。 结论:float 型可以作为 key,但是由于精度的问题,会导致一些诡异的问题,慎用之。 |
优雅地关闭 channel根据 sender 和 receiver 的个数,分下面几种情况:
对于 1,2,只有一个 sender 的情况就不用说了,直接从 sender 端关闭就好了,没有问题。重点关注第 3,4 种情况。 第 3 种情形下,优雅关闭 channel 的方法是: 解决方案就是增加一个传递关闭信号的 channel,receiver 通过信号 channel 下达关闭数据 channel 指令。senders 监听到关闭信号后,停止发送数据。 最后一种情况,优雅关闭 channel 的方法是: 和第 3 种情况不同,这里有 M 个 receiver,如果直接还是采取第 3 种解决方案,由 receiver 直接关闭信号 channel 的话,就会重复关闭信号 channel,导致 panic。因此需要增加一个中间人,M 个 receiver 都向中间人 channel 发送关闭数据 channel 的“请求”,中间人收到第一个请求后,就会直接下达关闭数据 channel 的指令(通过关闭信号 channel,这时就不会发生重复关闭的情况,因为信号 channel 的发送方只有中间人一个)。另外,这里的 N 个 sender 也可以向中间人 channel 发送关闭数据 channel 的请求。 另外如果,我们把中间人 channel 的容量声明成 Num(senders) + Num(receivers),因为中间人 channel 容量足够大,所以 senders 和 receivers 可以直接向中间人 channel 发送请求而不用担心阻塞。 |
channel 中的 happened-before 关系
关于 channel 的发送(send)、发送完成(send finished)、接收(receive)、接收完成(receive finished)的 happened-before 关系如下:
第一条,我们从源码的角度看也是对的,send 不一定是 happened before receive,因为有时候是先 receive,然后 goroutine 被挂起,之后被 sender 唤醒,send happened after receive。但不管怎样,要想完成接收,一定是要先有发送。 第二条,缓冲型的 channel,当第 n+m 个 send 发生后,有下面两种情况: 若第 n 个 receive 没发生。这时,channel 被填满了,send 就会被阻塞。那当第 n 个 receive 发生时,sender goroutine 会被唤醒,之后再继续发送过程。这样,第 n 个 receive 一定 happened before 第 n+m 个 send finished。 若第 n 个 receive 已经发生过了,这直接就符合了要求。 第三条,也是比较好理解的。第 n 个 send 如果被阻塞,sender goroutine 挂起,第 n 个 receive 这时到来,先于第 n 个 send finished。如果第 n 个 send 未被阻塞,说明第 n 个 receive 早就在那等着了,它不仅 happened before send finished,它还 happened before send。 第四条,回忆一下源码,先设置完 closed = 1,再唤醒等待的 receiver,并将零值拷贝给 receiver。 例一: var done = make(chan bool)
var msg string
func aGoroutine() {
msg = "hello, world"
done <- true
}
func main() {
go aGoroutine()
<-done
println(msg)
} 加了 这里依赖的 happened before 就是前面讲的第一条。第 n 个 send 一定 happened before 第 n 个 receive finished,即 例二: var done = make(chan bool)
var msg string
func aGoroutine() {
msg = "hello, world"
<-done
}
func main() {
go aGoroutine()
done <- true
println(msg)
} 根据第三条规则,对于非缓冲型的 channel,第 n 个 receive 一定 happened before 第 n 个 send finished。也就是说, 在 |
go1.13+ 在init中使用了flag, test时报错: flag provided but not defined: -test.XXX
添加代码
或直接在
flag.Parse()
前添加golang/go#31859 (comment)
The text was updated successfully, but these errors were encountered: