Golang的小知识点
值方法和指针方法
Go
type MyInterFace interface {
GetName() string
GetId() uint
}
type MyStruct struct {
Name string
Id uint
}
func (m *MyStruct) GetName() string {
return m.Name
}
func (m MyStruct) GetId() uint {
return m.Id
}无论是值类型还是指针类型,都能调用interface声明的方法。 但是区别在于:
- 当值类型时,发生值拷贝,上述方法访问是不同的地址;
- 指针类型则指向的是同一内存地址;
执行先后顺序
先说结论:初始化顺序为 常量 -> 全局变量 -> init方法 。 需要特别注意的点:
- 定义全局变量定义后,在函数方法中初始化该全局变量不能使用
:=来初始化值,因为:=只能在函数内部使用,声明并初始化的是局部变量, 在当前作用域生效, 不影响全局变量。 - 定义全局变量并初始化时,引用了另一个未初始化的全局变量的值或成员(此时这个全局变量为nil)时,会出现空指针问题。建议全局变量定义好后,在
init方法中专门初始化这些全局变量。
struct实现了哪些interface
组合的方式允许了struct和interface实现可以分离写在不同的地方,当代码多了以后就不好找struct实现了哪些interface。以下面代码为例:
Go
package demo
type UnImplInterface interface {
NotImpl() error
}
type PersonInterface interface {
GetName() string
}
type Person struct {
Name string
}
func (p *Person) GetName() string {
return p.Name
}以下方法均可以检查struct是否实现了interface:
- 借助于编译器,增加一行代码:
var _ demo.PersonInterface = (*demo.Person)(nil),编译即可,若为实现,则编译器报错 ; - 借助于
go doc命令,需要先go install这个package然后执行:go doc -all <package>.<struct>,输出struct的完整定义,查看其中是否实现了interface的方法; - 借助于反射这个package,不建议新手使用 ;
最好是养成在定义struct的位置用空接口断言(即方法1)的习惯。
以下是借助于Golang的反射机制,来检查struct是否实现了interface的demo:
Go
// 注意struct实现interface的形式,是类型实现interface还是指针类型实现interface
// 下面的代码是类型实现了interface, 如果是指针类型实现,则下面的代码的 struct{} 需要改为 *struct{}
// 1. reflect查看struct所有的method,检查是否实现了interface的方法
t := reflect.TypeOf(struct{})
for i := 0; i < t.NumMethod(); i++ {
m := t.Method(i)
fmt.Println(m.Name, m.Type, m.Index)
}
// 2. reflect检查struct是否实现了interface
t := reflect.TypeOf(struct{})
interfaceType := reflect.TypeOf((*interface)(nil)).Elem()
fmt.Println(t.Implements(interfaceType))