Go语言结构篇

1.1struct的简介
◼ Go通过结构体struct和interface实现oop(面向对象编程)
◼ struct的成员(也叫属性或字段)可以是任何类型,如普通类型、复合类型、函数、map、interface、struct等
图1:struct成员类型图
1.2 struct详解
(1) struct定义

//示例
type Student struct {
	name string
	age int     	// 小写私有成员(对外不可见)
	Class string	// 首字母大写则该成员为公有成员(对外可见)
}

(2) struct声明与初始化

var stu1 Student				//struct声明
var stu2 *Student= &Student{} 	//简写stu2 := &Student{}
var stu3 *Student = new(Student)//简写stu3 := new(Student)

(3) 自定义构造函数

// 通过工厂模式自定义构造函数方法
func Newstu(name1 string,age1 int,class1 string) *Student {
	return &Student{name:name1,age:age1,Class:class1}
}		
func main() {
	stu1 := Newstu(“jacky",25,"math")
	fmt.Println(stu1.name) // jacky
}

(4) struct tag–json应用场景
应用场景示例,json序列化操作(序列化演示)

type Student struct {
	Name string `json:"name"`
	Age int `json:"age"`
}
func main() {
	var stu = Student{Name: "darren", Age: 34}
	data, err := json.Marshal(stu)
	if err != nil {
	fmt.Println("json encode failed err:", err)
		return
	}
	fmt.Println(string(data)) //{"name":"darren","age":34}
}

(5) struct匿名成员(字段、属性)

◼ 结构体中,每个成员不一定都有名称,也允许字段没有名字,即匿名成员。
◼ 匿名成员的一个重要作用,可以用来实现oop中的继承。
◼ 同一种类型匿名成员只允许最多存在一个。
◼ 当匿名成员是结构体时,且两个结构体中都存在相同字段时,优先选择最近的字段。

type Person struct {
	Name string
	Age int
}
type Student struct {
	score string
	Age int
	Person // 匿名内嵌结构体
}
//代码:1-4.go
func main() {
	var stu = new(Student)
	stu.Age = 34 //优先选择Student中的Age
	fmt.Println(stu.Person.Age, stu.Age) // 0,34
}

(6) struct-继承、多继承
◼ 当结构体中的成员也是结构体时,该结构体就继承了这个结构体,继承了其所有的方法与属性,当然有多个结构体成员也就是多继承。
◼ 访问父结构中属性也使用“.”,但是当子结构体中存在和父结构中的字段相同时候,只能使用:"子结构体.父结构体.字段"访问父结构体中的属性,如上面示例的stu.Person.Age
◼ 继承结构体可以使用别名,访问的时候通过别名访问,如下面示例man1.job.Salary

type Person struct {
	Name string
	Age int
}
type Teacher struct {
	Salary int
	Classes string
}
type man struct {
	sex string
	job Teacher //别名,继承Teacher 这个时候就不是匿名了
	Person //继承Person
}
func main() {
	var man1 = new(man)
	man1.Age = 34
	man1.Name = "darren"
	man1.job.Salary = 100000
	fmt.Println(man1, man1.job.Salary) //&{ {8500 } {darren 34}} 8500
}

(7) struct-结构体中的方法
方法是什么
◼ Go方法是作用在接受者(个人理解成作用对象)上的一个函数,接受者是某种类型的变量,因此方法是一种特殊类型的函数。
◼ 接收者可以是任何类型,不仅仅是结构体,Go中的基本类型(int,string,bool等)也是可以,或者说数组的别名类型,甚至可以是函数类型。但是,接受者不能是一个接口类型,因为接口是一个抽象的定义,方法是一个具体实现。
◼ 一个类型加上它的方法等价于面向对象中的一个类。一个重要的区别是:在 Go 中,类型的代码和绑定在它上面的方法的代码可以不放置在一起,它们可以存在在不同的源文件,唯一的要求是:它们必须是同一个包的。
◼ 类型 T(或 *T)上的所有方法的集合叫做类型 T(或 *T)的方法集。
◼ 因为方法是函数,所以同样的,不允许方法重载,即对于一个类型只能有一个给定名称的方法。但是如果基于接收者类型,是有重载的:具有同样名字的方法可以在 2 个或多个不同的接收者类型上存在,比如在同一个包里这么做是允许的
◼ 别名类型不能有它原始类型上已经定义过的方法(因为别名类型和原始类型底层是一样的)。

type Person struct {
	Name string
	Age int
}
func (p Person) Getname() string { //p代表结构体本身的实列,类似python中的self,这里p可以写为self
	fmt.Println(p.Name)
	return p.Name
}
func main() {
	var person1 = new(Person)
	person1.Age = 34
	person1.Name = "darren"
	person1.Getname() // darren
}

(8) struct-结构体中的方法-方法和函数的区别

◼ 方法只能被其接受者调用
◼ 接收者是指针时,方法可以改变接受者的值(或状态),函数也能做到
◼ 接受者和方法必须在同一个包内

(9) 方法的接受者是值或者指针的区别

◼ 当接受者是一个值的时候,这个值是该类型实例的拷贝
◼ 如果想要方法改变接受者的数据,就在接受者的指针类型上定义该方法。否则,就在普
通的值类型上定义方法。
**总结:**指针方法和值方法都可以在指针或者非指针上被调用。也就是说,方法接收者是
指针类型时,指针类型的值也是调用这个方法,反之亦然。

func (c Circle) expand() {
	c.Radius *= 2    // 值方法不能改变值
}

func (c *Circle) expand2() {
	c.Radius *= 2	// 指针方法可以改变值
}
func main() {
	var c = Circle{Radius: 50}
	fmt.Println(c.Area(), c.Circumference())
	// 指针变量调用方法形式上是一样的
	var pc = &c
	pc.expand2()
	fmt.Println(pc.Area(), pc.Circumference())
}

(10) struct-内存分布

go中的结构体内存布局和c结构体布局类似,每个成员的内存分布是连续的

type Student struct {
	Name 	string	// 16 byte
	Age 	int64	// 8 byte
	wight 	int64	// 8 byte
	high 	int64	// 8 byte
	score 	int64	// 8 byte
}

*什么是字节对齐:*访问特定类型变量时,需要访问特定内存地址,各种类型数据按照一定规则在空间排列,而不是顺序排放,这就是对齐。

*为什么要对齐:*不同的平台的寻址方式不同,有的需要从偶地址开始访问,如果从奇数地址访问,需要读取两次,再进行高低字节的整合,效率就下降了。

对齐规则:
1.结构体成员变量的偏移地址是其对齐字节数的整数倍
2.结构体成员变量的偏移地址能够被其自身整除
3.结构体的大小是最大类型成员长度的整数倍

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值