zoukankan      html  css  js  c++  java
  • Golang 指针

    什么是指针

    基本数据类型和数组,变量存储的是,也就是值类型。

    指针类型,变量存储的是另外一个变量的内存地址,也就是指针类型。

    package main
    
    import "fmt"
    
    func main()  {
    	var name string = "smile"
    
    	var ptr *string = &name
    
    	fmt.Printf("变量name的值是%v\nptr指针的值是%v",name,ptr)
    }
    

    程序的输出结果:

    变量name的值是smile
    ptr保存的值是0xc000088220
    ptr本身的内存为0xc0000ce018
    

    结合程序,画出内存示意图如下:

    image-20211204220800003

    在上图中,变量name的值是smile,存储在地址为0xc00004c230的内存中。变量ptr存储了变量name的地址。现在可以说ptr指向name

    指针的声明

    一个指针变量指向一个值得内存地址

    类似于变量和常量,在使用指针前你需要声明指针。指针的声明格式如下:

    var var_name *var_type
    

    var_type为指针类型,var_name为指针的变量名,*号用于指定变量是作为一个指针。

    var ip *int //指向整形
    var if *float //指向浮点型
    

    让我们写一些代码

    package main
    
    import "fmt"
    
    func main()  {
    	var name string = "smile"
    	
    	var pname *string
    
    	pname = &name
    
    	fmt.Printf("panme的类型是%T\n值是%v",pname,pname)
    }
    

    '&'操作符用来获取到一个变量的地址。在上面的程序中,我们讲name的地址赋予pname(pname的类型为*string)。现在我们说pname指向了name。程序的输出为:

    panme的类型是*string
    值是0xc000088220
    

    指针的空值

    指针的空值为nil

    package main
    
    import "fmt"
    
    func main()  {
    	name := "smile"
    
    	var pname *string
    
    	if pname == nil {
    		pname = &name
    
    		fmt.Println(pname)
    	}
    }
    

    在上面的程序中 pname的初始值为nil。接着将name的地址赋值给pname。程序的输出结果为:

    pname的值为 <nil>
    pname的值为 0xc00004c230
    

    指针解引用

    解引用指针的意思是通过指针访问指向的值。指针pname的解引用就是*pname

    让我们通过一个程序看一下它是怎么工作的。

    package main
    
    import "fmt"
    
    func main()  {
    	name := "smile"
    	pname := &name
    
    	fmt.Printf("pname的值为%v\n指向的值为%v",pname,*pname)
    }
    

    我们将panme解引用并打印这个解引用得到的值。和我们预期的一样,程序打印的是name的值smile,程序的输出为:

    pname的值为0xc00004c230
    指向的值为smile
    

    让我们写一个程序,该程序使用指针改变name的值

    package main
    
    import "fmt"
    
    func main()  {
    	name := "smile"
    	pname := &name
    
    	fmt.Printf("pname的值为%v\n指向的值为%v\n",pname,*pname)
    
    	*pname = "dylan"
    
    	fmt.Printf("pname的值为%v\n指向的值为%v\n",pname,*pname)
    }
    

    在上面的程序中,我们将pname指向的值进行了修改,因此name的值也被改变了。程序的输出结果为:

    name的值为smile
    name的值为dylan
    

    传递指针给函数

    package main
    
    import "fmt"
    
    func main()  {
    	var name string = "smile"
    
    	fmt.Println("函数调用之前的值",name)
    
    	change(&name)
    
    	fmt.Println("函数调用之前的值",name)
    
    }
    
    func change(value *string)  {
    	*value = "dylan"
    }
    

    我们name的地址符传递给函数change。在函数change内部,通过解引用修改了name的值。程序的输出结果如下:

    函数调用之前的值 smile
    函数调用之前的值 dylan
    

    不要传递指向数组的指针给函数,而是使用切片

    假设我们需要通过函数修改一个数组。一个办法是将数组的指针作为参数传递给函数

    package main
    
    import "fmt"
    
    func main()  {
    	var names [3]string = [3]string{"smile","易文杰","dylan"}
    
    	fmt.Println("调用函数之前",names)
    
    	changeArray(&names)
    
    	fmt.Println("调用函数之后",names)
    }
    
    func changeArray(array *[3]string)  {
    	(*array)[0] = "quest"
    	array[1] = "aron"
    }
    

    上面的程序中,数组names的地址传递给函数changeArray在函数中,我们通过解引用的方式将数组的第一个和第二个元素进行重新赋值。程序的输出:

    调用函数之前 [smile 易文杰 dylan]
    调用函数之后 [quest aron dylan]
    

    array[1](*array)[1]`的简写

    虽然可以通过传递数组指针给函数的方式来修改原始数组的值,但在Go中不是惯用的方式。我们可以使用切片来完成同样的事情。

    采用切片方式重写上面的程序

    package main
    
    import "fmt"
    
    func main()  {
    	var names [3]string = [3]string{"smile","易文杰","dylan"}
    
    	fmt.Println("调用函数之前",names)
    
    	changeArray(names[:])
    
    	fmt.Println("调用函数之后",names)
    }
    
    func changeArray(array []string)  {
    	array[0] = "quest"
    	array[1] = "aron"
    }
    

    我们将一个切片传递给changeArray函数,在函数内部。切片的第一个和第二个元素被修改。程序的输出为:

    调用函数之前 [smile 易文杰 dylan]
    调用函数之后 [quest aron dylan]
    

    所以请不要将数组的指针作为参数传递给函数,而是使用切片。这样代码更加简洁,在Go中更常被使用

    Go不支持指针运算

    package main
    
    import "fmt"
    
    func main()  {
    	var ptr *int
    
    	i := 1
    
    	ptr = &i
    
    	ptr ++
    
    	fmt.Println(ptr)
    }
    

    上面的程序将会报错:invalid operation: ptr++ (non-numeric type *int)

  • 相关阅读:
    广义mandelbrot集,使用python的matplotlib绘制,支持放大缩小
    cs229 斯坦福机器学习笔记(一)-- 入门与LR模型
    Scrapy研究探索(三)——Scrapy核心架构与代码执行分析
    matlab各类数据l图像之间的转化
    开源重磅,java内容管理系统CMS,点击就可以编辑,保存,轻松构建自己的站点
    Android4.4 ContentResolver查询图片无效 及 图库删除 添加图片后,ContentResolver不更新的问题解决
    03002_MySQL数据库的安装和配置
    [.Net Core] 简单使用 Mvc 内置的 Ioc
    Asp.Net MVC中Action跳转
    EF的增删改查
  • 原文地址:https://www.cnblogs.com/ywjcqq/p/15656554.html
Copyright © 2011-2022 走看看