Skip to content

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:

  1. 借助于编译器,增加一行代码:var _ demo.PersonInterface = (*demo.Person)(nil),编译即可,若为实现,则编译器报错 ;
  2. 借助于go doc命令,需要先go install这个package 然后执行:go doc -all <package>.<struct> ,输出struct的完整定义,查看其中是否实现了interface的方法;
  3. 借助于反射这个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))