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

    指针

      本章围绕字符串、数字、数组、切片、map、channel、结构体与指针赋值及函数传参的应用剖析

    字符串

    字符串本身也是StringHeader的结构体,包含Data指针与字符串长度,如下

    type StringHeader struct {
        Data uintptr
        Len  int
    }

    Data指向的内存地址不可更改,字符串赋值和传参只是拷贝了StringHeader中Data和Len的值

    package main
    
    import "fmt"
    
    func main()  {
    	str := "Hello World!"
    	var data string
    	data = str
    	// 拷贝str中Data与Len
    	fmt.Println(data)
    	data = "Hello Go!"
    	// 修改data的值 在内存中生成新的StringHeader结构体 并赋值给data
    	fmt.Println(data)
    	// str内存未改变
    	fmt.Println(str)
    }
    
    //Hello World!
    //Hello Go!
    //Hello World!

    当声明变量为字符串指针时,变量赋值时对象一定是字符串内存地址,函数传参时拷贝的也是内存地址而已 

    package main
    
    import "fmt"
    
    
    func main()  {
    	str := "Hello World!"
    	var ptr *string
    	// 错误方法 str是字符串类型非指针类型
    	//ptr = str
    	// 正确方式 获取str的地址 赋值给ptr
    	ptr = &str
    
    	fmt.Println(ptr)
    	fmt.Println(*ptr)
    }
    
    //0xc0000421c0
    //Hello World!
    

      

     数字

    数字未找到对应的结构体,数字类型赋值、指针、函数传参与字符串一致,不可修改(修改等同于重新赋值)

    package main
    
    import "fmt"
    
    func main()  {
    
    	number := 10
    	var ptr *int
    	// 错误方法 str是字符串类型非指针类型
    	//ptr = str
    	// 正确方式 获取str的地址 赋值给ptr
    	ptr = &number
    
    	fmt.Println(ptr)
    	fmt.Println(*ptr)
    }
    
    //0xc00000a0b8
    //10
    

      

     数组

    数组赋值、函数传参时,进行都是内存拷贝,数据都会拷贝一份,新的数组修改不影响被赋值的数组

    package main
    
    import "fmt"
    
    func main()  {
    	list1 := [4] int{1,2,3,4}
    
    	list2 := list1
    	list2[0] =100
    	fmt.Println(list1)
    	fmt.Println(list2)
    }
    
    //[1 2 3 4]
    //[100 2 3 4]

    数组指针,指针修改时不需要加*的;修改时,原数组更改

    package main
    
    import "fmt"
    
    func main()  {
    	list := [4]int{1,2,3,4}
    	// 声明时指定数组大小
    	var ptr *[4]int
    	ptr = &list
    	// 错误赋值
    	//*ptr[0] =100
    	// 正确方式
    	ptr[0] = 100
    	fmt.Println(list)
    	fmt.Println(*ptr)
    }
    
    //[100 2 3 4]
    //[100 2 3 4]
    

    切片

    切片结构体 SliceHeader 如下

    type SliceHeader struct {
        // 指向数组内存地址 赋值时拷贝的是数组地址
        Data uintptr
        // 长度
        Len  int
        // 申请空间
        Cap  int
    }
    

    赋值、copy、函数传参时只是拷贝了结构体中的变量。详情Go语言【数据结构】切片

    package main
    
    import "fmt"
    
    func main()  {
    	slice1 := []int{1,2,3,4}
    
    	slice2 := slice1
    	slice2[0] =100
    	fmt.Println(slice1)
    	fmt.Println(slice2)
    }
    
    //[100 2 3 4]
    //[100 2 3 4]
    

     切片指针,下面方式都不可以修改

    package main
    
    import "fmt"
    
    func main() {
    	slice1 := []int{1,2,3,4}
    	var ptr *[]int
    	ptr = &slice1
    
    	// 下面两种方式都不可以修改
    	ptr[0] =100
    	*ptr[0] =100
    	fmt.Println(slice1)
    	fmt.Println(*ptr)
    }
    
    //[1 2 3 4]
    //[1 2 3 4]
    

      

    channel

    通道在赋值时,指向的都是同一块内存地址

    package main
    
    import "fmt"
    
    func main() {
    	 chan1 := make(chan string,1)
    	 chan2 := chan1
    	 chan2 <- "hello"
    	 data := <-chan1
    	 fmt.Println(data)
    	 // 指向同一块地址
    	 fmt.Println(chan1)
    	 fmt.Println(chan2)
    }
    
    //hello
    //0xc000088000
    //0xc000088000

    同时,通道也支持指针

    package main
    
    import "fmt"
    
    func main() {
    	 chan1 := make(chan string,1)
    	 chan2 := &chan1
    	 *chan2 <- "hello"
    	 data := <-chan1
    	 fmt.Println(data)
    	 fmt.Println(chan1)
    	 fmt.Println(chan2)
    }
    
    //hello
    //0xc000038060
    //0xc000006028
    

      

    结构体 

    那么重点来了,结构体赋值和指针有何区别,先看戏结构体生成的三种方式,其中第二种方式和第三中方式一致

    package main
    
    import "fmt"
    
    type Phone struct {
    	color string
    	name string
    }
    
    func main() {
    	// 第一种生成方式  生成结构体对象
    	phone1 :=Phone{"Red","Iphone"}
    	fmt.Println(phone1.color)
    	fmt.Println(phone1.name)
    	fmt.Println(phone1)
    
    	// 第二种生成方式  生成结构体指针
    	phone2 :=&Phone{"Red","Iphone"}
    	fmt.Println(phone2.color)
    	fmt.Println(phone2.name)
    	fmt.Println(phone2)
    
    	// 第三种生成方式  生成结构体指针
    	phone3 := new(Phone)
    	phone3.color = "Red"
    	phone3.name = "Iphone"
    	fmt.Println(phone3.color)
    	fmt.Println(phone3.name)
    	fmt.Println(phone3)
    }
    
    //Red
    //Iphone
    //{Red Iphone}
    //Red
    //Iphone
    //&{Red Iphone}
    //Red
    //Iphone
    //&{Red Iphone}

    结构体赋值,等同于拷贝了结构体中的变量,函数传参与赋值一样

    package main
    
    import "fmt"
    
    type Phone struct {
    	color string
    	name string
    }
    
    func main() {
    	// 赋值
    	phone1 :=Phone{"Red","Iphone"}
    
    	phone2 := phone1
    	phone2.color = "Green"
    	fmt.Println(phone1.color)
    	fmt.Println(phone2.color)
    }
    
    //Red
    //Green

     而指针只是拷贝了结构体的内存地址,修改会影响原来的值

    package main
    
    import "fmt"
    
    type Phone struct {
    	color string
    	name string
    }
    
    func main() {
    	// 赋值
    	phone1 :=&Phone{"Red","Iphone"}
    
    	phone2 := phone1
    	phone2.color = "Green"
    	fmt.Println(phone1.color)
    	fmt.Println(phone2.color)
    }
    
    //Green
    //Green
    

      

  • 相关阅读:
    (转)获取枚举属性的值
    C#调用C++类(以COM组件的形式)
    托管DirectX,从MDX到SlimDX的转换(转)
    数字地球影像服务后台数据读取粗糙问题
    DevExpress控件EditValue_Changed事件(延迟问题)
    Visual Studio 2008经常性卡死的其中一种解决办法
    It's not too late to start!
    Gcc编译器 linux
    UNIX系统中的进程 linux
    图算法套汇问题 linux
  • 原文地址:https://www.cnblogs.com/lianzhilei/p/11563853.html
Copyright © 2011-2022 走看看