• Go语言学习之路-9-结构体


    什么是结构体

    回顾下slice和map他们都是单类型的

    
    func main() {
    // 切片或者数组的类型只能存一种
    s1 := []int{0, 1, 2, 3, 4, 5}
    // map也是同样它的这个类型的值也只能是单类型的
    m1 := map[string]string{"name": "eson", "addr": "hebei"}
    
    fmt.Println(s1, m1)
    }
    

    那如果想存储多种类型怎么办?使用结构体:struct

    
    // Person struce save person property
    type Person struct {
    name string
    age int
    }
    
    func main() {
    p1 := Person{name: "eric", age: 18}
    fmt.Printf("%v
    ", p1)
    }
    

    总结下:

    结构体是一组数据,它是一个复合类型(每个数据有自己的类型)

    自定义类型&类型别名

    除了标准的:字符串、数字、小数、布尔值我们可以通过type关键字自定义类型

    // PersonAge 自定义一个类型它有uint8的所有特性
    type PersonAge uint8
    

    类型别名go1.9版本之后的新功能

    package main
    
    import "fmt"
    
    // NewAge 自定义类型
    type NewAge uint
    
    // PersonAge go1.9之后引用了类型别名
    // 类型别名规定:TypeAlias只是Type的别名,本质上TypeAlias与Type是同一个类型。
    type PersonAge = uint8
    
    func main() {
    var a1 NewAge
    var a2 PersonAge
    
    fmt.Printf("自定义类型: %T
    ", a1) // 自定义类型: main.NewAge
    fmt.Printf("类型的别名: %T
    ", a2) // 类型的别名: uint8
    }
    

    类型别名规定:TypeAlias只是Type的别名,本质上TypeAlias与Type是同一个类型。好比一个人本身有中文名字又启用了一个英文名字,这个应为名字指向也是同一个人

    区别:

    自定义类型是一个独立的数据类型,但是类型别名他的类型还是它指向的数据类型

    使用结构体

    定义结构体

    type 类型名 struct {
        字段名 字段类型
        字段名 字段类型
        …
    }
    

    解释:

    • 类型名:标识自定义结构体的名称,在同一个包内不能重复
    • 字段名:标识结构体字段名。同一个结构体内的字段名必须唯一
    • 字段类型:标识结构体字段的具体类型
    type Person struct {
    	name string
    	age  uint
    }
    

    声明使用

    标准声明方式

    func main() {
    	// 标准声明方式
            // 当我们定义了一个变量后默认就使用了这个结构体的零值
    	var p1 Person
    	fmt.Printf("%v
    ", p1)
    	p1.name = "eric"
    	fmt.Printf("%v
    ", p1)
    }
    

    实例化指针

    func main() {
    	// p1 := new(Person) 
    	// 或者采用
    	p1 := &Person{}
    	fmt.Printf("%v
    ", p1)
    }
    

    new或者取址符会返回一个指针类型的结构体,什么使用指针类型的结构体呢?

    • 结构体很大的时候不希望每次使用的时候都COPY一份内存数据

    实例化先声明一个变量在赋值(没有初始化实例化一般都会使用零值),初始化是在声明的时候就赋值

    初始化声明(常用)

    package main
    
    import "fmt"
    
    type person struct {
    	name string
    	age  int
    }
    
    func main() {
    	// 键值对初始化
    	p1 := person{name: "eson", age: 18}
    
    	// 列表初始化
    	p2 := person{"eric", 18}
    
    	// 指针初始化(&或new)
    	p3 := &person{name: "fire", age: 18}
    
    	fmt.Printf("%v,%v,%v", p1, p2, p3)
    }
    

    匿名结构体

    在一些需要临时使用一个结构体的场景的时候,可以使用匿名结构体

    package main
    
    import "fmt"
    
    func main() {
    	// 匿名结构体
    	var user struct {
    		name string
    		age  int
    	}
    	user.name = "eson"
    	user.age = 18
    	// user的类型是: struct { name string; age int }
    	fmt.Printf("user的类型是: %T
    ", user)
    	// user的值:{eson 18}
    	fmt.Printf("user的值:%v
    ", user)
    }
    

    结构体的指针优化

    看下面的例子

    package main
    
    import "fmt"
    
    type person struct {
    	name string
    	age  int
    }
    
    func main() {
    	p1 := &person{name: "John", age: 18} // 初始化一个person的结构体指针变量
    	// 当我们使用的时候怎么用?
    }
    

    如下方式调用,是不是怪怪的?

    package main
    
    import "fmt"
    
    type person struct {
    	name string
    	age  int
    }
    
    func main() {
    	p1 := &person{} // 初始化一个person的结构体指针变量
    	// 当我们使用的时候怎么用?
    	(*p1).name = "John"
    	(*p1).age = 18
    	fmt.Printf("%v
    ", p1) // &{John 18}
    }
    

    go给我们做了一个语法糖,我们可以在调用指针类型的结构体的时候可以进行简写成如下

    package main
    
    import "fmt"
    
    type person struct {
    	name string
    	age  int
    }
    
    func main() {
    	p1 := &person{} // 初始化一个person的结构体指针变量
    	p1.name = "John"
    	p1.age = 18
    	fmt.Printf("%v
    ", p1)  // &{John 18} 它还是一个指针类型的
    }
    

    结构体嵌套

    package main
    
    import "fmt"
    
    // Address 包含省份和城市
    type Address struct {
    	Province string
    	City     string
    }
    
    // Info 包含年龄、email等信息
    type Info struct {
    	Age   int
    	Email string
    }
    
    // 长辈
    type Account struct {
    	Email string
    }
    
    // Student 学生信息
    type Student struct {
    	Name    string
    	Address Address
    	Info
    	Account
    }
    
    func main() {
    	s1 := &Student{Name: "eson",
    		Info:    Info{Age: 18, Email: "eson@gamil.com"},
    		Address: Address{Province: "hb", City: "hs"},
    		Account: Account{Email: "eson@gamil.com"},
    	}
    	fmt.Println(s1.Name)
    	// 匿名字段可以直接访问
    	fmt.Println(s1.Age)
    	// 非匿名字段需要输入输入输入全部
    	fmt.Println(s1.Address.City)
    	// 如果匿名字段冲突了需要输入全部的
    	fmt.Println(s1.Info.Email)
    	fmt.Println(s1.Account.Email)
    }
    
    
  • 相关阅读:
    Binary Tree Maximum Path Sum
    4Sum
    Candy
    Simplify Path
    Max Points on a Line
    ZigZag Conversion
    Two Sum
    Effective_STL 学习笔记(十二) 对STL线程安全性的期待现实一些
    Effective_STL 学习笔记(十一) 理解自定义分配器的正确用法
    Effective_STL 学习笔记(九) 在删除选项中仔细选择
  • 原文地址:https://www.cnblogs.com/luotianshuai/p/14260536.html
Copyright © 2020-2023  润新知