zoukankan      html  css  js  c++  java
  • go struct结构体

    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 }

    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
    ", &r1.p1.x)
    	fmt.Printf("p1.y addr:%p
    ", &r1.p1.y)
    	fmt.Printf("p2.x addr:%p
    ", &r1.p2.x)
    	fmt.Printf("p2.y addr:%p
    ", &r1.p2.y)
    	fmt.Println()
    	fmt.Println()
    	//r2的内存布局
    	fmt.Printf("p1.x addr:%p
    ", &(r2.p1.x))
    	fmt.Printf("p1.y addr:%p
    ", &(r2.p1.y))
    	fmt.Printf("p2.x addr:%p
    ", &(r2.p2.x))
    	fmt.Printf("p2.y addr:%p
    ", &(r2.p2.y))
    	fmt.Printf("p1:%p
    ", &r2.p1)
    	fmt.Printf("P2:%p
    ", &r2.p2)
    }

    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()
    }
    

    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)
    }
    

    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)
    
    }
    

    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))
    }
    

    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)
    }
    

    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)
    }
    

    方法

    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)
    }
    
  • 相关阅读:
    布隆过滤器(Bloom Filter)
    什么是分布式账本
    什么是非对称加密?非对称加密算法介绍
    ANDROID DisplayManager 服务解析一
    ANDROID DisplayManager 服务解析一
    ANDROID DisplayManager 服务解析一
    ANDROID DisplayManager 服务解析一
    第1章 数据结构绪论
    第1章 数据结构绪论
    第1章 数据结构绪论
  • 原文地址:https://www.cnblogs.com/shhnwangjian/p/7451355.html
Copyright © 2011-2022 走看看