golang学习笔记4——结构体

Posted yubo_725

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang学习笔记4——结构体相关的知识,希望对你有一定的参考价值。

结构体格式

golang中的结构体格式如下:

type 结构体名称 struct 
	字段名 字段类型
	字段名 字段类型

下面定义一个结构体Point,有坐标x, y两个整型字段:

type Point struct 
	x int
	y int

同种类型的字段可以写在一行,如下代码:

type Color struct 
	r, g, b byte

结构体的初始化

结构体的定义只是一种内存布局的描述,只有当结构体实例化时,才会真正地分配内存。因此必须在定义结构体并实例化后才能使用结构体的字段。

如下代码所示:

package main

import "fmt"

type Point struct 
	x int
	y int


func main() 
	var p Point  // 或者 p := Point
	p.x = 1
	p.y = 0
	// 打印:1 0
	fmt.Println(p)

可以直接使用.来访问结构体的成员变量。

除了使用上面的方式声明并初始化结构体外,还可以使用new关键字,如下代码所示:

package main

import "fmt"

type Point struct 
	x int
	y int


func main() 
	p := new(Point)  // 也可以使用 p := &Point
	p.x = 1
	p.y = 0
	fmt.Println(p)

var p Point这种方式不同的是,使用new关键字创建的是Point类型的指针变量,golang中同样可以使用.来访问结构体指针的成员变量。

也可以在声明结构体变量时直接初始化:

func main() 
	p := Point
		x: 1,
		y: 0,
	
	fmt.Println(p)

下面的代码中定义了两个结构体:猫和人,人养了一只宠物,代码如下:

package main

import "fmt"

// 结构体 猫
type Cat struct 
	Name   string
	Weight float32
	Color  string


// 结构体 人
type Person struct 
	Name string
	Age  int
	// 养了一只猫
	Pet  *Cat


func main() 
	// 初始化一只猫的指针
	pet := &Cat
		Name:   "kenny",
		Weight: 20.3,
		Color:  "white",
	
	// 初始化一个人
	person := Person
		Name: "zhangsan",
		Age:  25,
		Pet:  pet,
	
	fmt.Println(person)

匿名结构体

// 结构体作为函数参数
func test(msg *struct 
	ID   string
	Name string
	Age  int
) 
	fmt.Printf("id: %v, name: %v, age: %v", msg.ID, msg.Name, msg.Age)


func main() 
	// 调用函数,传入匿名的结构体
	test(&struct 
		ID   string
		Name string
		Age  int
	
		"asdfasdf",
		"wangwu",
		25,
	)
	// 打印结果:id: asdfasdf, name: wangwu, age: 25

模拟构造函数

golang没有Java中的类的概念,自然也没有类的构造方法,但是可以模拟结构体的构造函数,比如如下代码:

// 结构体: 猫
type Cat struct 
	Name  string
	Color string


// 模拟猫的构造函数,传入姓名
func NewCatWithName(name string) *Cat 
	return &Cat
		Name: name,
	


// 模拟猫的构造函数,传入猫的颜色
func NewCatWithColor(c string) *Cat 
	return &Cat
		Color: c,
	


func main() 
	// 调用“构造函数”创建两个猫
	c1 := NewCatWithColor("black")
	c2 := NewCatWithName("kenny")
	fmt.Println(c1, c2)

模拟继承

golang中在一个结构体中嵌入另一个结构体,来完成类似于面向对象编程中的类的继承,如下代码:

// 结构体 表示动物
type Animal struct 
	Color string


// 结构体 猫
type Cat struct 
	Animal  // 这里嵌入了Animal这个结构体,类似于Cat继承了Animal
	Name string


func main() 
	cat := Cat
	// Cat类中没有声明Color,但是由于嵌入了Animal,所以也有了Color字段
	cat.Color = "black"
	cat.Name = "haha"
	fmt.Println(cat)

给结构体添加方法

在面向对象编程中,我们除了给类添加成员变量,还可以为类添加方法,在golang中定义结构体时,只能定义结构体中的成员变量,要为结构体添加方法,只能使用函数来实现,如下代码:

// 定义结构体 猫
type Cat struct 
	Color string


// 为猫添加一个Eat()方法
func (c *Cat) Eat() 
	fmt.Printf("The %s cat is eating...\\n", c.Color)


func main() 
	cat := &Cat
		Color: "black",
	
	// The black cat is eating...
	cat.Eat()

上面的代码为猫这个结构体添加了一个Eat方法,在定义Eat函数时,func后面紧接着的是(c *Cat),这个(c *Cat)叫做接收器,表示该函数作用的对象,因为是*Cat,所以表示Eat方法作用于Cat指针上,于是在main函数里,初始化了一个cat指针,就可以直接使用cat.Eat()来调用Eat函数了。

golang里的接收器分为两种:指针类型的接收器和非指针类型的接收器。

上面的代码中展示的是指针类型的接收器,其实也可以定义非指针类型的接收器,如下代码:

// 点,包含两个坐标值
type Point struct 
	X int
	Y int


// 非指针类型的接收器
func (p Point) Add(a, b int) Point 
	return Point
		X: p.X + a,
		Y: p.Y + b,
	


func main() 
	p := Point
		X: 0,
		Y: 0,
	
	p1 := p.Add(1, 1)
	fmt.Println(p1)

在上面的代码中,AddPoint的一个方法,该方法接受两个整型数据,返回一个PointAdd函数的接收器是一个Point结构体,而非结构体的指针类型。

指针类型接收器与非指针类型接收器的区别:

  • 小对象比较适合使用非指针类型的接收器,因为其复制时速度较快
  • 大对象比较适合使用指针类型的接收器,因为大对象的复制性能较差,使用指针速度更快

给基本数据类型添加方法

// 定义一个MyInt类型(就是int型)
type MyInt int

// 给MyInt型的变量添加一个isZero方法
func (i MyInt) isZero() bool 
	return i == 0


func main() 
	var i MyInt = 3
	fmt.Println(i.isZero())

方法和函数的统一调用

这里说的方法,指的是与某个结构体关联起来的函数,该函数具有接收器;而普通的使用func定义的,称为函数。下面的代码展示了方法与函数的统一调用:

type Person struct 


// 定义Person的sing方法
func (p *Person) sing(song string) 
	fmt.Printf("the person is singing %s\\n", song)


// 定义一个单独的sing函数
func sing(song string) 
	fmt.Printf("call function sing, the song is %s\\n", song)


func main() 
	// 定义f
	var f func(string)

	p := &Person
	// 将f赋值为Person的成员方法
	f = p.sing

	f("My heart will go on")

	// 将f赋值为独立的函数
	f = sing
	f("My heart will go on")

上面的代码证明了,如果方法与函数具有相同的签名,则可以使用与它们签名一致的变量保存该方法或函数。

类型内嵌结构体

golang中的结构体在声明时,可以只写字段类型而不写字段名称,这种结构体称为类型内嵌或匿名字段类型内嵌,如下代码所示:

// 定义Data结构体,该结构体字段只有类型没有名称
type Data struct 
	string
	int
	float32


func main() 
	// 初始化结构体
	data := &Data
		string:  "zhangsan",
		int:     20,
		float32: 80.5,
	
	// 打印: &zhangsan 20 80.5
	fmt.Println(data)

结构体的内嵌与初始化

下面以一个例子说明结构体的内嵌,房子由门和窗户组成,如下代码:

// 窗户
type Window struct 
	Width  int
	Height int


// 门
type Door struct 
	Width  int
	Height int


// 房子
type House struct 
	Window
	Door


func main() 
	// 初始化House的方式
	house := &House
		Window: Window
			Width:  10,
			Height: 10,
		,
		Door: Door
			Width:  20,
			Height: 45,
		,
	
	fmt.Println(house)

上面的代码如果把Door这个结构体去掉,而直接把Door的结构写在House里,就成了嵌套的匿名结构体,如下代码:

// 窗户
type Window struct 
	Width  int
	Height int


// 房子
type House struct 
	Window
	// 门直接以内嵌形式声明,而不单独声明结构体
	Door struct 
		Width  int
		Height int
	


func main() 
	house := &House
		Window: Window
			Width:  10,
			Height: 10,
		,
		// 初始化House时给Door赋值的方法如下:
		Door: struct 
			Width  int
			Height int
		
			Width:  20,
			Height: 45,
		,
	
	fmt.Println(house)

以上是关于golang学习笔记4——结构体的主要内容,如果未能解决你的问题,请参考以下文章

Golang学习笔记-复合类型

golang中定义的某个interface作为函数的入参时

go语言学习笔记 — 基础 — 复合数据类型 — 结构体:结构体方法(行为)

Golang中结构体Struct

Golang中结构体Struct

Golang中结构体Struct