结构体


自定义类型

Go语言中可以使用type关键字来定义自定义类型。自定义类型是定义了一个全新的类型。我们可以基于内置的基本类型定义,也可以通过struct定义。

type alias = Type //类型别名
type alias Type   //类型定义

类型别名并没有产生新的类型,但是类型定义产生了

结构体定义

type name struct{
    arg1 type1
    agr2 type2
}

结构体实例化

package main

import "fmt"

type Person struct {
 name string
 age  int
}

func main() {
 // var p = Person{"ffacs", 19}
 p := Person{"ffacs", 19}
 fmt.Printf("name:%s\nage:%d\n", p.name, p.age)
}

匿名结构体

很好理解,你把type name去掉,最右边其实就是一个匿名结构体

package main

import "fmt"

func main() {
 var tem = struct {
  name string
  age  int
 }{"ffacs", 20}
 fmt.Printf("%s %d", tem.name, tem.age)
}

结构体指针

在go中结构体指针不用->可以直接用.,这是语言给的语法糖

package main

import "fmt"

type Person struct {
 name string
 age  int
}

func main() {
 ffacs := new(Person)
 ffacs.name = "ffacs"
 ffacs.age = 20
 fmt.Printf("%s %d\n", ffacs.name, ffacs.age)
}

取结构体的地址实例化

package main

import "fmt"

type Person struct {
 name string
 age  int
}

func main() {
    ffacs := &Person{} //等于new(Person)
 ffacs.name = "ffacs"
 ffacs.age = 20
 fmt.Printf("%s %d\n", ffacs.name, ffacs.age)
}

使用键值对初始化

package main

import "fmt"

type Person struct {
 name string
 age  int
}

func main() {
 ffacs := &Person{
  name: "ffacs",
  age:  20,
 }
 fmt.Printf("%s %d\n", ffacs.name, ffacs.age)
}

构造函数

Go语言的结构体没有构造函数,我们可以自己实现。 例如,下方的代码就实现了一个person的构造函数。 因为struct是值类型,如果结构体比较复杂的话,值拷贝性能开销会比较大,所以该构造函数返回的是结构体指针类型。

func newPerson(name string, age int) *Person {
 return &person{
        name,
        age,
 }
}

方法和接收者

Go语言中的方法(Method)是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者(Receiver)。接收者的概念就类似于其他语言中的this或者 self

func (receName receType) funcName(args) returnType {
}
  • 接收者变量:接收者中的参数变量名在命名时,官方建议使用接收者类型名称首字母的小写,而不是selfthis之类的命名。例如,Person类型的接收者变量应该命名为 pConnector类型的接收者变量应该命名为c等。
  • 接收者类型:接收者类型和参数类似,可以是指针类型和非指针类型。
  • 方法名、参数列表、返回参数:具体格式与函数定义相同。
package main

import "fmt"

type Person struct {
 name string
 age  int
}

func (this Person) laugh() {
 fmt.Printf("I`am %s,hahahaha!", this.name)
}
func main() {
 ffacs := Person{"ffacs", 20}
 ffacs.laugh()
}

指针类型的接收者

指针类型的接收者由一个结构体的指针组成,由于指针的特性,调用方法时修改接收者指针的任意成员变量,在方法结束后,修改都是有效的。这种方式就十分接近于其他语言中面向对象中的this或者self。 例如我们为Person添加一个SetAge方法,来修改实例变量的年龄。

package main

import "fmt"

type Person struct {
 name string
 age  int
}

func (this *Person) SetAge(newAge int) {
 this.age = newAge
}
func main() {
 ffacs := Person{"ffacs", 20}
 ffacs.SetAge(10)
 fmt.Println(ffacs.age)
}

注意:上面的代码中ffacs是一个值,但是仍能通过编译,因为编译器对其进行了隐式转换,变成了&ffacs.SetAge()

值类型的接收者

当方法作用于值类型接收者时,Go语言会在代码运行时将接收者的值复制一份。在值类型接收者的方法中可以获取接收者的成员值,但修改操作只是针对副本,无法修改接收者变量本身。

任意类型添加方法

在Go语言中,接收者的类型可以是任何类型,不仅仅是结构体,任何类型都可以拥有方法。 举个例子,我们基于内置的int类型使用type关键字可以定义新的自定义类型,然后为我们的自定义类型添加方法。

package main

import "fmt"

//MyInt 将int定义为自定义MyInt类型
type MyInt int

//SayHello 为MyInt添加一个SayHello的方法
func (m MyInt) SayHello() {
 fmt.Println("Hello, 我是一个int。")
}
func main() {
 var m1 MyInt
 m1.SayHello() //Hello, 我是一个int。
 m1 = 100
 fmt.Printf("%#v  %T\n", m1, m1) //100  main.MyInt
}

注意事项: 非本地类型不能定义方法,也就是说我们不能给别的包的类型定义方法。

结构体的匿名字段

结构体允许其成员字段在声明时没有字段名而只有类型,这种没有名字的字段就称为匿名字段。

//Person 结构体Person类型
type Person struct {
 string
 int
}

func main() {
 p1 := Person{
  "ffacs",
  20,
 }
 fmt.Printf("%#v\n", p1)        //main.Person{string:"ffacs", int:20}
 fmt.Println(p1.string, p1.int) //ffacs 20
}

匿名字段默认采用类型名作为字段名,结构体要求字段名称必须唯一,因此一个结构体中同种类型的匿名字段只能有一个。

嵌套结构体

一个结构体中可以嵌套包含另一个结构体或结构体指针。

嵌套匿名结构体

//Address 地址结构体
type Address struct {
 Province string
 City     string
}

//User 用户结构体
type User struct {
 Name    string
 Gender  string
 Address //匿名结构体
}

func main() {
 var user2 User
 user2.Name = "小王子"
 user2.Gender = "男"
 user2.Address.Province = "山东"    //通过匿名结构体.字段名访问
 user2.City = "威海"                //直接访问匿名结构体的字段名
 fmt.Printf("user2=%#v\n", user2) //user2=main.User{Name:"小王子", Gender:"男", Address:main.Address{Province:"山东", City:"威海"}}
}

注意:当访问结构体成员时会先在结构体中查找该字段,找不到再去匿名结构体中查找。

嵌套结构体的字段名冲突

嵌套结构体内部可能存在相同的字段名。这个时候为了避免歧义需要指定具体的内嵌结构体的字段。

结构体的“继承”

Go语言中使用结构体也可以实现其他编程语言中面向对象的继承。

注意:需要是匿名结构体

结构体字段的可见性

结构体中字段大写开头表示可公开访问,小写表示私有(仅在定义当前结构体的包中可访问)。


文章作者: ffacs
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 ffacs !
  目录