struct结构体

  • 用来自定义复杂数据结构
  • struct里面可以包含多个字段(属性),字段可以是任意类型
  • struct类型可以定义方法,注意和函数的区分
  • struct类型是值类型
  • struct类型可以嵌套
  • Go语言没有class类型,只有struct类型

make 用来创建map、slice、channel  

new用来创建值类型

 1、struct 声明

type 标识符 struct {
       field1 type
       field2 type
}

样例:

type Student struct {
       Name string
       Age int
       Score int
}

 2、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.Score)

 3、struct定义的几种形式:

• a. var stu Student  //值类型
• b. var stu *Student = new(Student)  //引用类型
• c. var stu *Student = &Student{}  //引用类型
• d. var stu Student = Student {}  //值类型

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

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

可以理解为语法糖,写stu.Name时底层会转成(*stu).Name 

4. struct的内存布局:struct中的所有字段在内存是连续的,布局如下:

type Rect1 struct { Min, Max Point }
type Rect2 struct { Min, Max *Point }

Struct在java中什么类型 struct里面还有struct_json

 

package main

import (
	"fmt"
)

type Point struct {
	x int
	y int
}

type Rect1 struct {
	p1 Point
	p2 Point
}

type Rect2 struct {
	p1 *Point
	p2 *Point
}

func main() {
	var r1 Rect1
	var r2 Rect2

	r2.p1 = new(Point)
	var r3 = new(Point)
	var r4 = new(Point)
	r2.p2 = new(Point)

	fmt.Println(r3, r4)
	//r1的内存布局
	fmt.Printf("p1.x addr:%p\n", &r1.p1.x)
	fmt.Printf("p1.y addr:%p\n", &r1.p1.y)
	fmt.Printf("p2.x addr:%p\n", &r1.p2.x)
	fmt.Printf("p2.y addr:%p\n", &r1.p2.y)
	fmt.Println()
	fmt.Println()
	//r2的内存布局
	fmt.Printf("p1.x addr:%p\n", &(r2.p1.x))
	fmt.Printf("p1.y addr:%p\n", &(r2.p1.y))
	fmt.Printf("p2.x addr:%p\n", &(r2.p2.x))
	fmt.Printf("p2.y addr:%p\n", &(r2.p2.y))
	fmt.Printf("p1:%p\n", &r2.p1)
	fmt.Printf("P2:%p\n", &r2.p2)
}

Struct在java中什么类型 struct里面还有struct_Struct在java中什么类型_02

 

5、链表定义

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

type Student struct {
       Name string
       Next* Student
}

样例一:

package main

import (
	"fmt"
)

type Student struct {
	Name  string
	Age   int
	Score float32
	next  *Student
}


func main() {
	var head Student
	head.Name = "hua"
	head.Age = 18
	head.Score = 100

	var stu1 Student
	stu1.Name = "stu1"
	stu1.Age = 23
	stu1.Score = 23

	head.next = &stu1
	var p *Student = &head
	for p != nil {
		fmt.Println(*p)
		p = p.next
	}
	fmt.Println()
}

Struct在java中什么类型 struct里面还有struct_Struct在java中什么类型_03

 

6、双链表定义

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

type Student struct {
       Name string
       Next* Student
       Prev* Student
}
package main

import (
	"fmt"
	"math/rand"
)

type Student struct {
	Name  string
	Age   int
	Score float32
	next  *Student
}

func trans(p *Student) {
	for p != nil {
		fmt.Println(*p)
		p = p.next
	}
	fmt.Println()
}

func insertTail(p *Student) {
	var tail = p
	for i := 0; i < 10; i++ {
		stu := Student{
			Name:  fmt.Sprintf("stu%d", i),
			Age:   rand.Intn(100),
			Score: rand.Float32() * 100,
		}
		tail.next = &stu
		tail = &stu
	}
}

func insertHead(p **Student) {
	for i := 0; i < 10; i++ {
		stu := Student{
			Name:  fmt.Sprintf("stu%d", i),
			Age:   rand.Intn(100),
			Score: rand.Float32() * 100,
		}
		stu.next = *p
		*p = &stu
	}
}


func addNode(p *Student, newNode *Student) {

	for p != nil {
		if p.Name == "stu9" {
			newNode.next = p.next
			p.next = newNode
			break
		}

		p = p.next
	}
}

func main() {
	var head *Student = new(Student)
	head.Name = "hua"
	head.Age = 18
	head.Score = 100

	insertTail(head)
	trans(head)
	insertHead(&head)
	trans(head)

	var newNode *Student = new(Student)

	newNode.Name = "stu1000"
	newNode.Age = 18
	newNode.Score = 100
	addNode(head, newNode)
	trans(head)
}

 7、二叉树定义

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

type Student struct {
       Name string
       left* Student
       right* Student
}

样例:

package main

import "fmt"

type Student struct {
	Name  string
	Age   int
	Score float32
	left  *Student
	right *Student
}

func trans(root *Student) {
	if root == nil {
		return
	}
	fmt.Println(root)

	trans(root.left)
	trans(root.right)

}

func main() {
	var root *Student = new(Student)

	root.Name = "stu01"
	root.Age = 18
	root.Score = 100

	var left1 *Student = new(Student)
	left1.Name = "stu02"
	left1.Age = 18
	left1.Score = 100

	root.left = left1

	var right1 *Student = new(Student)
	right1.Name = "stu04"
	right1.Age = 18
	right1.Score = 100

	root.right = right1

	var left2 *Student = new(Student)
	left2.Name = "stu03"
	left2.Age = 18
	left2.Score = 100

	left1.left = left2

	trans(root)
}

Struct在java中什么类型 struct里面还有struct_嵌套_04

 

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

package main

import "fmt"

type integer int

type Student struct {
	Number int
}

type Stu Student //alias

func main() {

	var i integer = 1000
	var j int = 100

	j = int(i)
	fmt.Println(j)

	var a Student
	a = Student{30}
	fmt.Println(a)

	var b Stu
	a = Student(b)
	fmt.Println(a)

}

Struct在java中什么类型 struct里面还有struct_json_05

 

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

Package model
type student struct {
       Name stirng
       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)

 

10、struct中的tag

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

package main

import (
	"encoding/json"
	"fmt"
)

type Student struct {
	Name  string `json:"student_name"`
	Age   int    `json:"age"`
	Score int    `json:"score"`
}

func main() {
	var stu Student = Student{
		Name:  "stu01",
		Age:   18,
		Score: 80,
	}

	data, err := json.Marshal(stu)
	if err != nil {
		fmt.Println("json encode stu failed, err:", err)
		return
	}

	fmt.Println(string(data))
}

Struct在java中什么类型 struct里面还有struct_字段_06

 

11、匿名字段

结构体中字段可以没有名字,即匿名字段。

package main

import(
    "fmt"
    "time"
)

type Car struct{
	name string
	age int
}

type Train struct{
	Car
	int
	start time.Time
}

func main() {
	var t Train
	t.Car.name = "001"
	t.Car.age = 100
	
	t.name = "train"
	t.age = 200
	
	fmt.Println(t)
}

Struct在java中什么类型 struct里面还有struct_嵌套_07

 12、组合和匿名字段

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

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

 13、实现String()

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

package main

import "fmt"

type Car struct {
	weight int
	name   string
}

func (p *Car) Run() {
	fmt.Println("running")
}

type Bike struct {
	Car
	lunzi int
}

type Train struct {
	Car
}

func (p *Train) String() string {
	str := fmt.Sprintf("name=[%s] weight=[%d]", p.name, p.weight)
	return str
}

func main() {
	var a Bike
	a.weight = 100
	a.name = "bike"
	a.lunzi = 2

	fmt.Println(a)
	a.Run()

	var b Train
	b.weight = 100
	b.name = "train"
	b.Run()

	fmt.Printf("%s", &b)
}

Struct在java中什么类型 struct里面还有struct_嵌套_08

 

方法

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

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

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

package main

import "fmt"

type Student struct {
	Name  string
	Age   int
	Score int
	sex   int
}

func (p *Student) init(name string, age int, score int) {
	p.Name = name
	p.Age = age
	p.Score = score
	fmt.Println(p)
}

func (p Student) get() Student {
	return p
}

func main() {
	var stu Student
	stu.init("stu", 10, 200)

	stu1 := stu.get()
	fmt.Println(stu1)
}

 

继承

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

package main

import "fmt"

type Car struct {
	weight int
	name   string
}

func (p *Car) Run() {
	fmt.Println("running")
}

type Bike struct {
	Car
	lunzi int
}

type Train struct {
	c Car
}

func main() {
	var a Bike
	a.weight = 100
	a.name = "bike"
	a.lunzi = 2

	fmt.Println(a)
	a.Run()

	var b Train
	b.c.weight = 100
	b.c.name = "train"
	b.c.Run()
}

 

多重继承

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

package main

import (
	"fmt"
)

type Cart1 struct {
	name string
	age  int
}

type Cart2 struct {
	name string
	age  int
}

type Train struct {
	Cart1
	Cart2
}

func main() {
	var t Train

	t.Cart1.name = "train"
	t.Cart1.age = 100

	fmt.Println(t)
}