起因:在看Gin-vue-admin框架源码的时候,发现config/zap.go下竟然有两个方法
ZapEncodeLevel和TransportLevel
// ZapEncodeLevel 根据 EncodeLevel 返回 zapcore.LevelEncoder
// Author [SliverHorn](https://github.com/SliverHorn)
func (z *Zap) ZapEncodeLevel() zapcore.LevelEncoder {
switch {
case z.EncodeLevel == "LowercaseLevelEncoder": // 小写编码器(默认)
return zapcore.LowercaseLevelEncoder
case z.EncodeLevel == "LowercaseColorLevelEncoder": // 小写编码器带颜色
return zapcore.LowercaseColorLevelEncoder
case z.EncodeLevel == "CapitalLevelEncoder": // 大写编码器
return zapcore.CapitalLevelEncoder
case z.EncodeLevel == "CapitalColorLevelEncoder": // 大写编码器带颜色
return zapcore.CapitalColorLevelEncoder
default:
return zapcore.LowercaseLevelEncoder
}
}
// TransportLevel 根据字符串转化为 zapcore.Level
// Author [SliverHorn](https://github.com/SliverHorn)
func (z *Zap) TransportLevel() zapcore.Level {
z.Level = strings.ToLower(z.Level)
switch z.Level {
case "debug":
return zapcore.DebugLevel
case "info":
return zapcore.InfoLevel
case "warn":
return zapcore.WarnLevel
case "error":
return zapcore.WarnLevel
case "dpanic":
return zapcore.DPanicLevel
case "panic":
return zapcore.PanicLevel
case "fatal":
return zapcore.FatalLevel
default:
return zapcore.DebugLevel
}
}
在简单了解了这两个方法的作用后
去查看了一下谁在调用,发现调用者是/core/internal/zap.go中的代码,这里就不放代码了
我看了之后很变扭,因为config作为配置包,为什么config/zap文件下会有初始化时用到的部分逻辑方法,还只是部分,不是全部。就好像将礼盒里的一整个蛋糕切出来一块,拿出来放到盒子上,一起交给寿星。
强迫症瞬间犯了
我想将这两个方法从config/zap.go中摘出来,也放到/core/internal/zap.go中
但是我发现就,这两个方法都是config/zap.go中Zap结构体的方法接收者
//config/zap.go中的结构体
type Zap struct {
Level string `mapstructure:"level" json:"level" yaml:"level"` // 级别
Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"` // 日志前缀
Format string `mapstructure:"format" json:"format" yaml:"format"` // 输出
Director string `mapstructure:"director" json:"director" yaml:"director"` // 日志文件夹
EncodeLevel string `mapstructure:"encode-level" json:"encode-level" yaml:"encode-level"` // 编码级
StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktrace-key" yaml:"stacktrace-key"` // 栈名
MaxAge int `mapstructure:"mintage" json:"max-age" yaml:"max-age"` // 日志留存时间
ShowLine bool `mapstructure:"show-line" json:"show-line" yaml:"show-line"` // 显示行
LogInConsole bool `mapstructure:"log-in-console" json:"log-in-console" yaml:"log-in-console"` // 输出控制台
}
若是直接将其抽出来,会报错。
那么现在问题就抽象为:方法接收者如何接收包外的结构体变量?
我模拟了一个简单的场景:现在有如下结构
├── a
│ └── a.go
├── b
│ └── b.go
有包a和包b,其中有a/b.go文件,a文件内容如下
package a
var AA = new (A)
type A struct {}
那么b中的内容,按照直觉应该是这么写的
package b
import "test/a"
func (*A)b() {}
func (*a.A)b() {}
func (*AA)b() {}
很抱歉,这样三种写法很明显都是错误的
那么你们能想到什么办法去实现这样的操作呢?
我的想法:
因为我是Java转Go,所以我想到Go和Java类比,Java确实不能在类外面去定义函数。
但继承是否可以,我们通过父类去调用子类的方法
package a
var AA = new (A)
type A struct {}
func (*A)AAA() {
}
package b
import "RestFul/test/a"
type B struct {
*a.A
}
func (*B)b() {
B.AAA("")
}
可以发现,当B中嵌入了匿名A也就是B继承了A后,我们自然可以实现接收B结构体,并使用其中的变量或方法
将这个思路使用到GVA框架中:
将代码粘过来,不再报错
拓展:通过刚刚的模拟,我又产生了一些疑问
如下,1.这三种调用方法在底层的顺序上,逻辑上,有什么区别?
2.为什么编译器提示我2 ,3 方法必须要有一个参数??(这点我最不理解)
欢迎各位大佬在评论区指点,永远保持学习的心态
package b
import "RestFul/test/a"
type B struct {
*a.A
}
func (*B)b() {
a.AA.AAA()
a.A.AAA("")
B.AAA("")
}