结构体:

1、用来自定义复杂数据结构

2、struct里面可以包含多个字段(属性)

3、struct类型可以定义方法,注意和函数的区分

4、strucr类型是值类型

5、struct类型可以嵌套

6、go语言中没有class类型,只有struct类型

struct声明:

         type  标识符 struct{

                   field1 type

                   field2 type

}

例子:

         type Student struct{

         Name string

         Age  int

         Score int

}

struct中字段访问,和其他语言一样,使用点

         例子:

                   var stu Student            //拿结构题定义一个变量

                   stu.Name=”tony”

                   stu.Age=18

                   stu.Score=20

                   fmt.Printf(“name=%s,age=%d,score=%d”,stu.Name,stu.Age,stu.Sore)

 

struct定义的三种形式    初始化的三种方式

         a、var stu Student

         b、var stu *Student=new(Student)

         c、var stu *Student=&Student{}

其中b和c返回的都是指向结构体的指针,访问形式如下:

         a、stu.Name、stu.Age  和stu.Score 或者(*stu).Name、 (*stu).Age等

如果是指针形式可以用上面的普通的方式访问,其实就自动转化为指针访问的形式

 

struct内存布局

例子:

 

链表的定义:

type Student struct{

         name string

         next* Student

}

每个节点包含下一个节点的地址,这样把所有的节点串起来,通常把链表中的每一个节点叫做链表头

 

遍历到最后一个元素的时候有个特点,就是next这个指针指向的是nil,可以从这个特点来判断是否是链表结束

单链表的特点:只有一个字段指向后面的结构体

         单链表只能从前往后遍历

双链表的特点:有两个字段,分别指向前面和后面的结构体

         双链表可以双向遍历

 

链表操作:

1、生成链表及遍历链表操作

 

插入链表的方法:

 

删除链表

删除指定节点:

思路:

1、遍历,

2、遍历当前节点的上个节点的next等于当前节点的下一个节点,这个节点就删除了

3、如果第一次没有找到,那么就往后移动位置,即当前节点的上级节点等于当前节点,当前节点的下一个节点赋值给当前节点,

4、下面这个代码是有问题的,主要是这是一个副本。头部插入会有问题

代码:

 

怎么在上面stu6后面插入一个节点?

思路:

1、首先生成一个节点,让这个节点的下一个节点等于stu6的下一个节点

2、再让stu6的下一个节点指向插入的这个节点

 

双向链表

         定义  type Student struct{

         Name sring

         next * Student

         prevn * Student

}

如果有两个指针分别指向前一个节点和后一个节点,我们叫做双链表

 

二叉树

定义:

         type Student struct{

         Name string

         left * Student

         right *Student

}

如果每个节点有两个指针分别用来指向左子树和右子树,我们把这样的结构叫做二叉树

对于二叉树,要用到广度优先或者深度优先的递归算法

 

 

下面是二叉树的类型图,下面的stu2的右边的孩子也可以是为nil,然后stu3如果没有孩子就叫做叶子节点,stu02是stu01的子树

 

代码:

下面采用递归的形式进行遍历二叉树,下面是深度优先的原理

如果要采取广度优先,那么每次遍历的时候就要把结果放到队列里面

 

前序遍历:是从根节点开始遍历的

 

结构体与方法

 

结构体是用户单独定义的类型,不能和其他类型进行强制转换

type Student struct{

         Number int

}

type Stu Student  //alias  别名   type 变量  类型 这个是定义类型的别名

var a Student

a=Student{30}

var b Stu

a=b   //这样赋值错误

a=Student(b)  //这样才可以

上面这两个Stu和Student是别名关系,但是这两个字段一样,并不是同一个类型,因为是type定义的

如:

 

工厂模式

golang中的struct没有构造函数,一般可以使用工厂模式来解决这个问题

Package model

type student Struct{

Name string

Age  int

}

 

func NewStudent(name string,age int)*Student{

         return &Student{   //创建实例

Name:name

Age:age

}

}

 

Package main

S:new(student)

S:model.NewStudent(“tony”,20)

再次强调

make用来创建map,slice ,channel

new 用来创建值类型

 

 

struct中的tag

我们可以为strct中的每一个字段,协商一个tag,这个tag可以通过反射机制获取到,最常用的场景就是json序列化和反序列化

type student struct{

         Name string  “this is name field” //每个字段写一个说明,作为这个字段的描述

         Age int      “this is age field”

}

 

json打包

json.Marshal()

注意:

json打包的时候,

1、必须要把结构体中的字段大写,才可以

下面是程序声明打包初始化的两种方式

 

匿名字段

 

结构体 中字段可以没有名字,叫做匿名字段

type Car struct{

         Name string

         Age int

}

 

type Train struct{

         Car                //匿名字段

         Start time.Time      //有名字段

         int                //匿名字段

}

匿名字段要怎么访问呢?

 

匿名字段冲突处理

 

对于上面的1这里有优先原则:

缩写形式,如果有两个结构体中有相同的字段,会优先找本身的字段

对于上面的2,必须要手动的指定某个字段才可以,不然会报错

 

方法:

golang中的方法是作用在特定类型的变量上,因此自定义类型,都可以有方法,而不仅仅是struct

定义: func (recevier type ) methodName(参数列表)(返回值列表){}

  

方法的调用

type A struct{

         a int

}

func (this A)test(){

         fmt.Println(this.a)

}

 

var t A

t.test()

上面的this就是下面的t,通过上面方法中的参数this.A就能获取当前结构体中的实例

 

方法和函数的区别:

1)函数调用 :function(variable,参数列表)

2)‘方法 variable.function(参数列表)

 

指针receiver vs值receiver

 本质上和函数的值传递和地址传递是一样的

方法的访问控制,通过大小写控制

继承

如果一个struct潜逃了另一个匿名结构体,那么这个结构可以直接访问匿名结构体的方法,从而实现了继承

如:

 

下面是方法的继承

 

组合和匿名函数

如果一个struct嵌套了另一个匿名结构体,那么这个结构体可以直接访问匿名结构体的方法,从而实现了继承

如果一个struct嵌套了另一个有名结构体,那么这个模式就叫做组合(一个结构体嵌套另一个结构体)

也可以说匿名字段是特殊的组合

 

 

多重继承

如果一个struct嵌套了多个匿名结构体,那么这个结构可以直接访问多个匿名结构体的方法,从而实现了多重继承

如果冲突的话,就需要带上结构体的名字来访问

 

实现String()  这是一个接口

如果一个变量实现了String()这个方法,那么fmt.Println默认会调用变量String()进行输出