Go 开发常用操作技巧--结构体

69 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第21天,点击查看活动详情

结构体是由一系列相同或不相同类型数据组成的数据集合。 结构体的成员(字段)的特性:

  • 字段名必须唯一
  • 字段有自己的类型和值
  • 字段的类型也可以是结构体,甚至是字段所在结构体的类型

结构体定义格式如下:

type 类型名 struct{
  字段1 类型1
  字段2 类型2
  //...
}

结构体初始化

type Mystruct struct {
	Name    string
	Address string
}

//方法一
var person Mystruct
person.Name = "test"
person.Address = "beijing"

//方法二
person1 := Mystruct{"test","beijing"}

//方法三
//(*person2).Name 等同于 person2.Name
var person2 = new(Mystruct)
person2.Name = "test"
person2.Address = "beijing"

//方法四
//(*Mystruct).Name 等同于 person3.Name
var person3 = &Mystruct{}
(*person3).Name = "test"
(*person3).Address = "beijing"

结构体排序

可以通过 sort.Slice() 函数进行结构体的排序

示例:

package main

import (
	"fmt"
	"sort"
)

type Mystruct struct {
	Name    string
	Address string
}

func main() {
	persons := []Mystruct{
		{"test2", "aa"},
		{"test1", "bb"},
		{"test3", "cc"},
	}
	fmt.Println(persons)
	sort.Slice(persons, func(i, j int) bool {
		return persons[i].Name < persons[j].Name || persons[i].Address < persons[j].Address
	})
	fmt.Println(persons)
}

运行结果:

[{test2 aa} {test1 bb} {test3 cc}]
[{test1 bb} {test2 aa} {test3 cc}]

结构体继承

Go 语言中没有 extends 关键字,不能像其他语言那样去实现类的继承。在Go中,使用的是 interface 实现的功能组合,以组合的形式来实现继承。

如下我们创建一个父类结构体 Father,再用子类 Child 继承父类,实现在 Child 中调用父类的方法,示例:

package main

import (
	"fmt"
)

type Father struct {
	Name string
}
func (f Father) Say(){
	fmt.Println("father...")
}

type Child struct {
	Father
}

func main() {
	child := Child{}
	child.Father.Say() // father...
	//直接使用下面的写法也可以,Go语言做了相关的优化,直接调用方法也可以找到父类中的方法
	child.Say() // father...
}

改写父类的方法

package main

import (
	"fmt"
)

type Father struct {
	Name string
}
func (f Father) Say(){
	fmt.Println("father...")
}

type Child struct {
	Father
}

func (c Child)Say(){
	fmt.Println("child start...")
	c.Father.Say()
	fmt.Println("child end...")
}

func main() {
	child := Child{}
	child.Father.Say()
	//被 child 改写后,下面调用的就是自身的方法
	child.Say()
}

运行结果:

father...
child start...
father...
child end...

匿名结构体

顾名思义,匿名结构体就是没有名字的结构体,示例如下:

package main

import "fmt"

func main() {
	book := struct {   // 无需事先声明
		title  string
		id     int
	}{
		title:  "Go语言",  // 定义完成之后,即可进行初始化  
		id:     123456,
	}
	fmt.Println("title ", book.title)
	fmt.Println("id", book.id)
}

// 打印结果
// title  Go语言
// id 123456

结构体字段标签

结构体字段标签(tag)是结构体额外的信息,用于对字段进行说明。在 json 序列化及对象关系映射时,会用到此标签。标签信息都是静态的,无需实例化结构体,可以通过反射来获得。

标签在结构体后面,由一个或多个键值组成,键值间使用空格分隔:
key1:"value1" key2:"value2"

使用反射获取结构体标签信息:

package main

import (
	"fmt"
	"reflect"
)

type Test struct {
	Name string `json:"name"`
}

func main() {
	var test = Test{}
	//反射获取标签信息
	typeTest := reflect.TypeOf(test)
	testFieldName, ok := typeTest.FieldByName("Name")
	if ok {
		fmt.Println(testFieldName.Tag.Get("json"))
	}
}

// 打印结果
// name

多态

  • 继承主要在于: 解决代码的复用性和可维护性;
  • 接口主要在于: 接口设计好各种规范方法,让其它自定义类型实现这些方法;
  • 接口比继承更加灵活,继承是满足is-a的关系,接口是满足like-a的关系;

Go 中的多态是通过接口实现的:

package main

import "fmt"

type People interface {
	Say()
}
type Student struct {}
type Teacher struct {}

func (p *Student) Say(){
	fmt.Println("Student...")
}

func (c *Teacher) Say(){
	fmt.Println("Teacher...")
}

func hello(p People) {
	p.Say()
}
func main(){
	var student = new(Student)
	var teacher = new(Teacher)
	hello(student)
	hello(teacher)
}

打印结果:

Student...
Teacher...