• GO学习笔记 之面向对象编程[结构体]


    1.结构体的开篇

    一个没有结构体的例子:

    package main
    
    import "fmt"
    
    func main()  {
        // 1.变量
        var cat01Name string = "cat_hei"
        var cat01Age int = 3
        fmt.Println(cat01Name,cat01Age)
        var cat02Name string = "cat_bai"
        var cat02Age int = 4
        fmt.Println(cat02Name,cat02Age)
        // 2.数组
        var catNames [2]string = [...]string{"hei","bai"}
        var catAges [2]int = [...]int{3,4}
        fmt.Println(catNames,catAges)
    
        // 
    }
    

    使用结构体:结构体对于其他语言就是对象

    2.GO语言面向对象编程说明

    1golang也支持面向对象编程(OOP,但是和传统的面向对象编程有区别,并不是纯粹的面向对象语言。所有我们说Golang支持面向对象编程特性是比较准确的。

    2Golang没有类(class,GO语言的结构体(struct)和其他语言的类(class)有同等的地位,你可以理解Golang是基于struct来实现OOP特性的。

    3Golang面向对象编程非常简洁,去掉了传统OOP语言的继承,方法重载,构造函数和析构函数,隐藏的this指针等待

    4Golang仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其他OOP语言不一样,比如继承:Golang没有extends关键字,继承是通过匿名字段来实现。

    5Golang面向对象(OOP)很优雅,OOP本身就是语言类型系统(type system)的一部分,通过接口(interface)关联,耦合性低,也非常灵活。面向接口编程的思想。

    结构体(类)----实例(变量)

    package main
    
    import "fmt"
    
    // // 定义一个结构体
    type Cat struct{
        Name string 
        Age int
        Color string
    }
    
    func main() {
        //使用结构体
        var cat1 Cat   // 使用一个结构体
        cat1.Name = "bai"
        cat1.Age = 2
        cat1.Color = "white"
        // fmt.Println(cat1)
        fmt.Println("Name = ",cat1.Name)
        fmt.Println("Age = ",cat1.Age)
        fmt.Println("Color = ",cat1.Color)
    
    }
    

    1.结构体是自定义的数据类型,代表一类事物。

    2.结构体变量(实例)是具体的,实际的,代表一个具体变量。

    结构体是一种值类型数据。

    声明结构体语法:

    type 结构体名称 struct {

    filed1  type

    field2  type

    field3  type

    }

    3.结构体的字段/属性

    1)基本介绍:

    1.从概念上加法:结构体字段=属性=field

    2.字段是结构体的一个组成部分,一般是基本数据类型,数组,也是引用类型。

    2)注意事项和细节说明

    1.字典声明语法变量,示例: 字段名  字段类型

    2.字段的类型可以为:基本类型、数组或引用类型

    3.在创建一个结构体变量,如果没有给字段赋值都有对应的默认值。大概如下:

    布尔类型是false,数值是0,字符串是””

    数组类型默认值和它的元素类型相关,比如 score[3] int则为[0,0,0]

    指针,slicemap的默认值是nil,即没有分配空间。

    4.结构体的字段是独立的,互不影响,一个结构体变量字段的更改,不影响另外一个。

    结构体里使用:数组,slicemap的数据

    package main
    
    import "fmt"
    
    // 如果结构体的字段为:指针,slice和map的默认值都是nil
    // 如果需要使用这些字段,需要先make才能使用
    
    type Person struct {
        Name string
        Age int
        Scores [5]float64   // 
        ptr *int  // 指针
        Slice []int  // 切片
        Map map[string]string   // map
    
    }
    
    func main(){
        // 定义结构体
        var person1 Person
        fmt.Println(person1)  // { 0 [0 0 0 0 0] <nil> [] map[]} 
    
        if person1.ptr == nil{
            fmt.Println("ok1")
        } 
        if person1.Slice == nil {
            fmt.Println("ok2")
        }
        if person1.Map == nil {
            fmt.Println("OK3")
        }
    
        // 使用slice先make
        person1.Slice = make([]int,10)
        person1.Slice[0] = 10
        fmt.Println(person1.Slice)
    
        // 使用map先make
        person1.Map = make(map[string] string)
        person1.Map["hh"] = "666"
        fmt.Println(person1.Map)
    }
    

    结构体里面的属性之间不会相互影响例子:

    package main
    
    import "fmt"
    
    type Cat struct{
        Name string
        Age int
    }
    
    func main(){
    
        // 
        var cat1 Cat
        cat1.Name = "bai"
        cat1.Age = 2
        cat2 := cat1
        cat2.Age = 3
        fmt.Println(cat1)
        fmt.Println(cat2)
    }
    

    4.创建结构体变量和访问结构体方式

    方式1:直接声明

    var person01 Person

    方式2{}

    p2 := Person{"two",20}

    方式3&

    var p3 *Person = new(Person)

    方式4

    例子如下:

    package main
    
    import "fmt"
    
    type Person struct{
        Name string
        Age int
    }
    
    func main(){
        // 方式1:var p1 Person
        var p1 Person
        p1.Name = "one"
        p1.Age = 19
        fmt.Println(p1)
    
        // 方式2:p2 := Person{"two",20}
        p2 := Person{"two",20}
        fmt.Println(p2)
    
        // 方式3:
        var p3 *Person = new(Person)   // p3为结构体的指针
        // 因为p3是个指针,因此标准的写法如下:
        (*p3).Name = "Three"
        (*p3).Age = 21
        fmt.Println(p3)
        // 可简化为:因为创建者底层对上面指针做了处理
        // p3.Name = "Three"
        // p3.Age = 21
    
        // 方式4:var p4 *Person = &Person()
        // p4为指针
        var p4 *Person = &Person{}  // 也可以直接在{}进行赋值
        (*p4).Name = "four"
        (*p4).Age = 22
        fmt.Println(p4)   // p4为结构体的指针
        fmt.Println(p4.Name)
        fmt.Println(p4.Age)
    }
    

    5.结构体的内存分配机制

    例:

    package main
    
    import "fmt"
    
    type Person struct{
        Name string
        Age int
    }
    
    func main(){
        // 以下p1 和 p2 共享一个内存地址
        var p1 Person
        p1.Age = 10
        p1.Name = "小明"
        var p2 *Person = &p1   // p2是一个指针
    
        fmt.Println((*p2).Age)  //golang中 (*p2) 与 p2相同
        fmt.Println(p2.Age)
    
        p2.Name = "SIX"
        fmt.Println(p2.Name)
        fmt.Println(p1.Name)
        fmt.Println((*p2).Name)
    }
    

    6.结构体的注意事项和使用细节

    1)结构体的所有字段的内存是连续的[1]

    2两个结构体间转换必须两个结构体字段相同[2]

    3)结构体进行type重新定义(相当于取别名),Golang认为是重新定义数据类型,但是互相之间可以强转。[2]

    4struct的每个字段,可以写上一个tag,tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化。

    例子1

    package main
    
    import "fmt"
    
    type Point struct {
        x int
        y int
    }
    
    type Rect struct {
        leftUp, rightDown Point
    }
    
    type RectPointer struct {
        leftUp, rightDown *Point
    }
    
    func main() {
        //
        r1 := Rect{Point{1, 2}, Point{3, 4}}
        // r1 有4个int ,在内存中是连续分布的
        fmt.Println("r1.leftUp.x地址:", &r1.leftUp.x)
        fmt.Println("r1.leftUp.y地址:", &r1.leftUp.y)
        fmt.Println("r1.rightDown.x地址:", &r1.rightDown.x)
        fmt.Println("r1.rightDown.x地址:", &r1.rightDown.y)
        // // 八进制 一个地址八个字节
        /*
            r1.leftUp.x地址: 0xc000054120
            r1.leftUp.y地址: 0xc000054128
            r1.rightDown.x地址: 0xc000054130
            r1.rightDown.x地址: 0xc000054138
        */
        fmt.Println("结构体下面的值为地址的情况")
        r2 := RectPointer{&Point{1, 2},&Point{3, 4}}
        fmt.Println("r2.leftUp.x地址:", &r2.leftUp.x)
        fmt.Println("r2.leftUp.y地址:", &r2.leftUp.y)
        fmt.Println("r2.rightDown.x地址:", &r2.rightDown.x)
        fmt.Println("r2.rightDown.x地址:", &r2.rightDown.y)
        fmt.Println(r2.rightDown.x)  //  x值
    }
    

    例2:

    package main
    
    import "fmt"
    
    type A struct{
        Num int
    }
    
    type B struct{
        Num int
    }
    
    func main()  {
        // 如果要在两个结构体间转换必须两个结构体字段相同
        // 字段个数,字段名称,字段类型相同
        var a A
        var b B
        a = A(b)  // 强转
        fmt.Println(a,b)
    

     例4:

    package main
    
    import "fmt"
    import "encoding/json"
    
    type Monster struct{
        Name string `json:"name"`   // `json:"name"` 这个就是结构体的标签
        Age int `json:"age"`        // 效果是可以首字母大写的变量可以在json返回小写
        Skill string `json:"skill"`
    }
    
    func main(){
    
        // 1.创建一个Monster变量
        monster := Monster{"ZEOR",25,"coding go"}
    
        // 2.将monster变量序列化为json格式的字符串
        jsononster,err := json.Marshal(monster)
        if err != nil{
            fmt.Println("json处理错误")
        }
        fmt.Println("jsononster:",string(jsononster))  // jsononster数据类型为bytes需求强转为string
    }
    

      

  • 相关阅读:
    OCP 062【中文】考试题库(cuug内部资料)第19题
    OCP 062【中文】考试题库(cuug内部资料)第18题
    OCP 062【中文】考试题库(cuug内部资料)第17题
    743. 网络延迟时间 力扣(中等) 最短路径SPFA,不熟练
    1337. 矩阵中战斗力最弱的 K 行 力扣(简单) 确实简单,结构体排序,二分也可
    171. Excel 表列序号 力扣(简单) 想不明白的题
    987. 二叉树的垂序遍历 力扣(困难) bfs+hash+优先队列 感觉还是简单的,就是复杂了点
    46. 全排列 力扣(中等) 容器或回溯
    1947. 最大兼容性评分和 周赛 力扣(中等) 排列next_permutation用法
    1104. 二叉树寻路 力扣(中等) 数学题,思考久了
  • 原文地址:https://www.cnblogs.com/hszstudypy/p/14232889.html
Copyright © 2020-2023  润新知