go语言中通常是为自定义类型定义方法,同时要求方法的定义和类型的定义必须在同一个包内。(不能为int、bool等预声明类型定义方法,因为他们的作用域是全局)
首先介绍一下c/c++与go语言结构体指针的区别:
#include <iostream>
#include<map>
using namespace std;struct T{
int a;
};int main(){
T t=T{
1};T *p=&t;cout<<p->a<<endl;cout<<(*p).a<<endl;return 0;
}
在c语言中,结构体指针访问结构体字段可以通过p->a或者(*p).a,但是在go语言中没有->
package mainimport "fmt"type T1 struct{
a int
}
func main(){
i:=&T1{
a:100}fmt.Println(i.a)fmt.Println((*i).a)
}
可以看出通过i.a和(*i).a都可以访问,这是因为内部编译器将i.a转换成(*i).a。(隐式间接引用)
方法值和方法表达式
package mainimport "fmt"type T1 struct{
a int
}
func (t T1)f1(i int){
fmt.Println(t.a+i)
}
func main(){
t:=T1{
1}//1)a、方法值调用f:=t.f1f(1)//1)b、方法值调用t.f1(1)//2)a、方法表达式调用f1:=(T1).f1f1(t,1)//2)b、方法表达式调用(T1).f1(t,1)
}
方法值类似于方法接收者,方法表达式类似于作为函数的第一个默认参数。
方法集
将接受者为值类型T的方法的集合记录为S,将接受者为指针类型T的方法的集合记录为S则:
1)T类型的方法集是S
2)T类型的方法集为S何S
在直接使用类型实例t(t T)调用方法是,无论是值类型还是指针类型,都可以调用类型的所有方法,编译器进行转换。
package mainimport "fmt"type T struct{
a int
}func(t T) get()int{
return t.a
}func(t *T)set(i int){
t.a=i
}func main(){
var a=10p:=&afmt.Println(p)i:=&T{
}i1:=T{
}i.set(10)i1.set(100)fmt.Println(i.get())fmt.Println((*i).get())fmt.Println(i1.get())
}
当通过类型字面量显示的进行方法调用,编译器无法转换
type A struct{
}
func (A)f1(){
}
func (*A)f2(){
}
//*A的方法集是f1和f2
(*A)(&struct{
}{
}).f1()
(*A)(&struct{
}{
}).f2()//方法值调用
(*A).f1((*A)(&struct{
}{
})) //方法表达式调用
//A的方法集是f1
(A)(struct{
}{
}).f1()
//(A)(struct{}{})f2() ?方法集不匹配