结构体和方法
结构体是数组组织的一种形式,类似面向对象语言中的class
。golang中使用结构体和结构体方法有面向对象的一些类似特性。
结构体定义
type 结构体名称 struct {
字段名1 类型1 `字段标签`
字段名2 类型2 `字段标签`
...
}
结构体字段名的大小写决定了这个结构体在包外是否可见。
type Stu struct{
Name string //包外可见
age int //包外不可见
}
结构体中的字段类型可以是任何类型,包括结构体本身,函数类型,接口类型。
type Inter interface{
FuncA(int)
}
type Ftype func(int)
type S struct {
fn Ftype //函数类型
inter Inter //接口类型
node *S //包含自己
Name string
}
结构体的标签可以通过结构体反射
获取,在结构体序列化和反序列化时长会见到。
比如结构体需要使用json序列化和反序列化是可能需要如下定义:
type Stu struct{
Name string `json:"name"`
No string `json:"number"`
age int //age对外不见不参与序列化
}
结构体初始化
type Stu struct{
Name string
age int
}
var stuA = Stu{"wida",18} //不带字段名初始化,必须按照结构体定义的顺序赋值
var stuB = Stu{Name:"amy",age:18} //带字段名初始化
var stuC = Stu{Name:"jenny"} //带字段名初始化,不给age初始化, age是int初始化值为0
一般在时间开发过程中,我们都建议使用带字段名初始化,这样防止在增加结构体字段的时候引起报错。
结构体还可以使用golang内置函数new
初始化。使用new
初始化返回的结构体指针。
var stuAPtr = new(Stu)
stuAPtr.Name = "wida"
stuAPtr.age = 18
大多数情况下我们可以使用取地址符&
来取代new
函数。
var stuAPtr = &Stu{"wida",18} //这个等效也上面的new 初始化
结构体嵌套
golang中结构体是可以嵌套的,A结构体
嵌套Base结构体
可以隐式获取Base结构体
的属性,实际上A结构体有个匿名字段为Base
在名字冲突的时候可以使用这个字段解决冲突问题
type Base struct {
Name string
Age int
}
type A struct{
Base
Gender int
}
type B struct {
Base
Name string
}
var a A
a.Gender = 1
a.Age = 18 //等同于a.Base.Age
a.Name = "wida" //等同于a.Base.Name
var b B
b.Age = 18
b.Name = "wida" //注意这个时候 b.Name是b自带的 而非b.Base.Name
b.Base.Name = "amy"
结构体方法
类似面向对象语言中的类方法,golang中结构体也有他的方法,在golang中结构体的方法有两中接收器(receiver),一种就是结构体结构体对象还一中是结构体结构体对象指针,需要注意二者在使用上的区别。
type Stu struct {
Name string
Age int
}
func (s Stu)GetName() string {
return s.Name
}
func (s Stu)SetName(name string) {
return s.Name = name
}
var a Stu
a.SetName("aaa")
fmt.Println(a) //{ 0} 这边SetName没有把a的Name赋值为aaa
SetName
正确的写法应该是
func (s *Stu)SetName(name string) {
return s.Name = name
}
a.SetName("aaa") //这边go会有一个隐式转换 a->*a
fmt.Println(a) //{aaa 0}
为什么结构体对象做接收器SetName
方法不起作用? 在golang中参数都是拷贝传递的,事实上接收器其实是特色的一个参数,结构体对象接收器的方法会把接收器对象拷贝一份,对新对象赋值操作当然不能改变老的对象,而由于指针结构体接收器拷贝的是指针,实际上是指向同一个对象,所以修改就能生效。 在实际开发过程中我们一般都会使用结构体对象指针接收器,不仅仅可以规避赋值不生效的问题,而且还可以防止大的对象发生拷贝的过程。
有个情况需要特别注意,在golang中nil
是可以作为接收器的。
func (s *Stu) SetName(name string) {
if s == nil {
return
}
s.Name = name
}
var aPtr *Stu //aPtr是指针 初值是nil
aPtr.SetName("ddd") //代码没有效果,但是不会报错
方法继承
类似结构体字段的继承,结构体A
内嵌另一个结构体B
时,属于B
的方法也会别A
继承。
type Base struct {}
func (b *Base)Say() {
fmt.Println("hi")
}
type A struct {
Base
}
var a A
a.Say()