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 main
import "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 main
import "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.f1
f(1)
//1)b、方法值调用
t.f1(1)
//2)a、方法表达式调用
f1:=(T1).f1
f1(t,1)
//2)b、方法表达式调用
(T1).f1(t,1)
}
方法值类似于方法接收者,方法表达式类似于作为函数的第一个默认参数。
方法集
将接受者为值类型T的方法的集合记录为S,将接受者为指针类型T的方法的集合记录为S则:
1)T类型的方法集是S
2)T类型的方法集为S何S
在直接使用类型实例t(t T)调用方法是,无论是值类型还是指针类型,都可以调用类型的所有方法,编译器进行转换。
package main
import "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=10
p:=&a
fmt.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() ❎方法集不匹配