• Go part 3 指针,栈与堆


    指针类型

    要明白指针,需要知道几个概念:指针地址指针类型指针取值

    取指针地址

    每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置,使用 & 放在变量前面进行“取指针地址”操作

    var int a = 10
    fmt.Println("address:", &a)
    
    // address: 0xc000098010

    获取指针类型

    package main
      
    import (
        "fmt"
    )
    
    func main(){
        var a int = 100
        addrA := &a
        fmt.Printf("pointer type: %T
    ",addrA)
    }
    
    运行结果:
    pointer type: *int
    

    从指针获取指针指向的值

    使用 * 方便指针地址前面进行“指针取值”操作

    package main
      
    import (
        "fmt"
    )
    
    func main(){
        var a int = 100
        addrA := &a
        fmt.Println("address:", addrA)
    
        valueA := *addrA
        fmt.Println("value:", valueA)
    }
    
    结果:
    address: 0xc000098010
    value: 100
    

    通过指针修改指针指向的值

    package main
      
    import (
        "fmt"
    )
    
    func main(){
        var a int = 100
        addrA := &a
        fmt.Println("address:", addrA)
    
        valueA := *addrA
        fmt.Println("value:", valueA)
    
        // modify
        *addrA = 1
        fmt.Println("modify value:", a)
    }
    
    运行结果:
    address: 0xc000098010
    value: 100
    modify value: 1
    

    练习1:写一个函数,使用指针交换两个整数的值

    package main
    
    import (
        "fmt"
    )
    
    func swap(a *int, b *int){
        *a, *b = *b, *a
    }
    
    
    func main(){
        var (
            a int = 100
            b int = 200
        )
    
        swap(&a, &b)
        fmt.Println(a, b)
    }
    
    运行结果:
    200 100
    

    练习2:使用指针变量获取命令行参数,经过 flag 包解析后,以指针类型返回,可定义变量接收命令行的数据

    package main
      
    import (
        "flag"
        "fmt"
    )
    
    func main(){
        // 接收命令行参数,key,默认值,帮助
        var mode = flag.String("mode", "", "process mode")
    
        flag.Parse()
        fmt.Println(*mode)
    }
    
    调用:
    go run pointer_03.go --mode "hello, world"
    
    运行结果:
    hello, world
    

    创建指针的另一种方法

    new() 函数可以创建一个对应类型的指针,创建过程会分配内存,被创建的指针指向的值为默认值

    package main
      
    import (
        "fmt"
    )
    
    func main(){
        var str *string = new(string)
        fmt.Println(*str)  
        *str = "hello, world~"
        fmt.Println(*str)
    }
    
    运行结果:
    // 空字符串
    hello, world~
    

    栈与堆

    什么是栈

    栈(Stack)是一种拥有特殊规则的线性表数据结构

    只允许往线性表的一端放入数据,之后在这一端取出数据,按照后进先出(LIFO,Last InFirst Out)的顺序,如下图:

    往栈中放入元素的过程叫做入栈,入栈会增加栈的元素数量,最后放入的元素总是位于栈的顶部,最先放入的元素总是位于栈的底部

    从栈中取出元素时,只能从栈顶部取出,不允许从栈底获取数据,也不允许对栈成员进行任何查看和修改操作

    什么是堆

    堆内存分配类似于往一个房间里摆放各种家具,家具的尺寸有大有小,分配内存时,需要找一块足够大小的空间来摆放家具,经过反复摆放和腾空家具后,房间里会变得乱七八糟,此时再往空间里摆放家具会存在虽然有足够的空间,但各空间分布在不同的区域,无法有一段连续的空间来摆放家具的问题,此时,内存分配器就需要对这些空间进行调整优化,如下图:

    堆分配内存和栈分配内存相比,堆适合不可预知大小的内存分配。但是为此付出的代价是分配速度较慢,而且会形成内存碎片

    堆和栈各有优缺点,该怎么在编程中处理这个问题呢?在 C/C++ 语言中,需要开发者自己学习如何进行内存分配,选用怎样的内存分配方式来适应不同的算法需求。比如,函数局部变量尽量使用栈;全局变量、结构体成员使用堆分配等。程序员不得不花费很多年的时间在不同的项目中学习、记忆这些概念并加以实践和使用。

    Go 语言将这个过程整合到编译器中,命名为“变量逃逸分析”。这个技术由编译器分析代码的特征和代码生命期,决定应该如何堆还是栈进行内存分配,即使程序员使用 Go 语言完成了整个工程后也不会感受到这个过程

    栈内存中通常分配值类型,包括 int,  float,  bool,  string 以及数组和 struct(结构体)

    堆内存中通常分配引用类型,通过 GC 回收,包括 pointer,  select,  map,  chan 等

    每天都要遇到更好的自己.
  • 相关阅读:
    Oracle修改字段类型
    JS解析JSON字符串
    C#Json转DataTable
    解决前台和后台传值出现中文乱码
    Oracle 存储过程简单语法
    EasyUI 冻结列
    EasyUI 数据网格行过滤
    windows计划任务
    C#日志文件
    bat 读取 ini 配置文件
  • 原文地址:https://www.cnblogs.com/kaichenkai/p/10911070.html
Copyright © 2020-2023  润新知