疑问的关键代码:
var _ log.Logger = (*stdLogger)(nil)
首先有这样一个结构,表示 log 结构器
// Logger is a logger interface.
type Logger interface {
	Log(level Level, keyvals ...interface{}) error
}
接下来按照正规流程,就是利用这个 logger 器,做些初始化 log 的方法
var _ Logger = (*stdLogger)(nil)
type stdLogger struct {
	log  *log.Logger
	pool *sync.Pool
}
// NewStdLogger new a logger with writer.
func NewStdLogger(w io.Writer) Logger {
	return &stdLogger{
		log: log.New(w, "", 0),
		pool: &sync.Pool{
			New: func() interface{} {
				return new(bytes.Buffer)
			},
		},
	}
}
问题就在这里为什么,明明这个 new 方法返回的是 stdLogger 这个结构,而为啥返回类型是 Logger,我发现个特别点就是第一行做了断言处理,这个是什么原理,一般断言也是把已知结构转成明确固定结构,为啥这里明明 stdLogger 结构体和 Logger 结构体完全不一样,就可以实现断言?
|      1johnwood      2021-08-14 21:34:52 +08:00 golang 的类型系统和 java 之类的不一样,他是鸭子类型系统,结构不用明确表明自己实现了某个接口,也没有 java 那样的“继承”。go 的倾向是组合优于继承。 回到问题,估计因为 stdLogger 里有嵌入的 log *log.Logger | 
|  |      2zzyphp111 OP | 
|  |      3zzyphp111 OP @johnwood #1 这也是我所以疑问的,你看 zap 的引入就没有嵌入 log *log.Logger,但也断言成功了,这是为什么    https://github.com/go-kratos/kratos/blob/main/examples/log/zap.go | 
|      4gjquoiai      2021-08-14 22:57:21 +08:00 一个编译时检查某个东西是否实现了某个接口的技巧,现在用的不多了,都用 linter 了 | 
|      6comwrg      2021-08-14 23:25:06 +08:00 4L 说的对,是用来编译期保证正确的实现了某个接口,而不是等着运行之后程序 panic | 
|  |      7EscYezi      2021-08-15 00:05:03 +08:00 via iPhone 只要实现了 Logger 所有的方法就实现了 Logger 接口 楼主提到的 stdLogger 和 zapLogger 可以断言成功是因为两个结构体都实现了 Logger 接口的 Log 方法,和内嵌的那个 log 成员没关系 | 
|  |      9EscYezi      2021-08-15 00:18:07 +08:00 via iPhone @johnwood #8 实例化的 stdLogger 啊,stdLogger 实现了 Logger 接口 | 
|  |      10EscYezi      2021-08-15 00:52:54 +08:00 可以尝试运行一下这段代码 package main import "fmt" type Logger interface { Log(...interface{}) } type myLogger struct { } func (l *myLogger) Log(...interface{}) { fmt.Println("my logger") } func main() { var l Logger = (*myLogger)(nil) l.Log("aaa") } | 
|  |      12zzyphp111 OP | 
|  |      13kksco      2021-08-16 13:53:49 +08:00  1 | 
|  |      15Ansen      2022-11-16 17:26:35 +08:00 |