指针

  本章围绕字符串、数字、数组、切片、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

  

最新文章

  1. .NET基础拾遗(5)多线程开发基础
  2. 产生某个区间的随机整数 int #Java
  3. java并发:同步容器&amp;并发容器
  4. SQL server的存储过程
  5. 面向初学者的 Windows 10 UWP 应用开发
  6. Android设计模式系列-组合模式
  7. InsertOnSubmit、InsertAllOnSubmit等区别 (转)
  8. JS模式--通用对象池的实现
  9. [0] JDK与JRE的区别
  10. fio2.1.10--README
  11. SEO页面优化以及如何对单页面应用进行SEO优化
  12. 织梦dedecms列表序号从0到1开始的办法 autoindex,itemindex标签
  13. 24个 CSS 高级技巧合集
  14. 002之MFCSocket异步编程
  15. ELK Deployed
  16. 走楼梯(walk) 解题报告
  17. 大数据系列之并行计算引擎Spark介绍
  18. native生成策略:由Hibernate根据所使用的数据库支持能力从identity、sequence或者等生成策略中选择一种
  19. 【乱码】Request QueryString 编码,传值乱码的几种情况和解决办法(单页,多页)
  20. [ActionScript 3.0] SharedObject的用法简介

热门文章

  1. XSS相关有效载荷及绕道的备忘录(下)| 文末有打包好的负载
  2. Vue.js最佳实践--给大量子孙组件传值(provide/inject)
  3. kali2.0升级
  4. redis不能保存bean对象
  5. html5表单上传控件Files筛选指定格式的文件:accept属性过滤excel文件
  6. Ingress-Nginx
  7. 将qemu使用的设备树dump出来
  8. django 使用新的虚拟环境
  9. Collaborative Spatioitemporal Feature Learning for Video Action Recognition
  10. K8S或docker的旁路容器注入排查