zoukankan      html  css  js  c++  java
  • Go语言

    区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针。

    要搞明白Go语言中的指针需要先知道3个概念:指针地址、指针类型和指针取值

     概念

    任何程序数据载入内存后,在内存都有他们的地址,这就是指针。而为了保存一个数据在内存中的地址,我们就需要指针变量。

    比如,“人生苦短,Let's go”这句,我想把它写入程序中,程序一启动这句话是要加载到内存(假设内存地址0x123456),我在程序中把这段话赋值给变量A,把内存地址赋值给变量B。这时候变量B就是一个指针变量。通过变量A和变量B都能找到这句话。

    Go语言中的指针不能进行偏移和运算,因此Go语言中的指针操作非常简单,我们只需要记住两个符号:

    &(取地址)和*(根据地址取值)

    指针地址和指针类型

    每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。

    Go语言中使用&字符放在变量前面对变量进行“取地址”操作。

    Go语言中的值类型(int、float、bool、string、array、struct)都有对应的指针类型,如:*int*int64*string等。

     取变量指针的语法:

    ptr := &v    // v的类型为T
    • v:代表被取地址的变量,类型为T
    • ptr:用于接收地址的变量,ptr的类型就为*T,称做T的指针类型。*代表指针。

    eg:

    func main() {
        a := 10
        b := &a
        fmt.Printf("a:%d ptr:%p
    ", a, &a) // a:10 ptr:0xc00001a078
        fmt.Printf("b:%p type:%T
    ", b, b) // b:0xc00001a078 type:*int
        fmt.Println(&b)                    // 0xc00000e018
    }

    我们来看一下b := &a的图示:

    指针取值

    在对普通变量使用&操作符取地址后会获得这个变量的指针,然后可以对指针使用*操作,也就是指针取值,代码如下。

    func main() {
        //指针取值
        a := 10
        b := &a // 取变量a的地址,将指针保存到b中
        fmt.Printf("type of b:%T
    ", b)
        c := *b // 指针取值(根据指针去内存取值)
        fmt.Printf("type of c:%T
    ", c)
        fmt.Printf("value of c:%v
    ", c)
    }

    结果:

    type of b:*int
    type of c:int
    value of c:10

    总结: 取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。

    • 对变量进行取地址(&)操作,可以获得这个变量的指针变量。
    • 指针变量的值是指针地址。
    • 对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值

    指针传值示例:

    func test(a1 [3]int)  {
        a1[0] = 100
    }
    // 接收一个指针,对指针取值
    func test1(a1 *[3]int)  {  // 只有指针类型才能用*方法取值
        a1[0] = 100
    }
    func main() {
        a := [3]int{1,2,3}
        test(a)  // 在函数的名称空间中复制了数组并赋值给变量a1
        fmt.Println(a)  // [1 2 3]
        test1(&a)  // test1函数的形参接收的是指针,所以需要传入指针
        fmt.Println(a)  // [100 2 3]  因为是通过指针拿到的同一个地址
    }

    new

    使用new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值。

     new针对值类型初始化得到指针

    签名

    func new(Type) *Type
    • Type表示类型,new函数只接受一个参数,这个参数是一个类型
    • *Type表示类型指针,new函数返回一个指向该类型内存地址的指针
    func main()  {
        var a = new(int)  // 得到一个int类型的指针
        fmt.Println(a)  // 0xc000054058
        *a = 10  // 给指针赋值
        fmt.Println(a)  // 0xc000054058 
        fmt.Println(*a)  // 10
    
        var c = new([3]int)
        fmt.Println(c)  // &[0 0 0]
        // (*c)[0] = 10
        c[0] = 10
        fmt.Println(*c)  // [10 0 0]
    }

    注意: var a *int只是声明了一个指针变量a但是没有初始化,指针作为引用类型需要初始化后才会拥有内存空间,才可以给它赋值

    make

    make也是用于内存分配的,区别于new,它只用于slice、map以及chan的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。make函数的函数签名如下:

    func make(t Type, size ...IntegerType) Type

    make函数是无可替代的,我们在使用slice、map以及channel的时候,都需要使用make进行初始化,然后才可以对它们进行操作。这个我们在上一章中都有说明,关于channel我们会在后续的章节详细说明。

    本节开始的示例中var b map[string]int只是声明变量b是一个map类型的变量,需要像下面的示例代码一样使用make函数进行初始化操作之后,才能对其进行键值对赋值:

    func main() {
        var b map[string]int
        b = make(map[string]int, 10)
        b["熊二"] = 100
        fmt.Println(b)
    }

    new与make的区别

    1. 二者都是用来做内存分配的。
    2. make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;
    3. 而new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。
  • 相关阅读:
    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
    11
    实战 迁移学习 VGG19、ResNet50、InceptionV3 实践 猫狗大战 问题
    tx2系统备份与恢复
    如何在Ubuntu 18.04上安装和卸载TeamViewer
    bzoj 3732 Network (kruskal重构树)
    bzoj2152 聪聪可可 (树形dp)
    牛客 216D 消消乐 (二分图最小点覆盖)
    牛客 197E 01串
    Wannafly挑战赛23
  • 原文地址:https://www.cnblogs.com/waller/p/11954121.html
Copyright © 2011-2022 走看看