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
Go语言【数据结构】指针的更多相关文章
- 浅谈c语言的指针
对于非计算机专业的同学,c语言的指针往往就是老师的一句“指针不考“就带过了.c语言的指针号称是c语言的灵魂,是c语言中最精妙的部分. 指针本质上也是变量,也就是一段内存,只是他的特殊之处是他存储的数据 ...
- C#委托与C语言函数指针及函数指针数组
C#委托与C语言函数指针及函数指针数组 在使用C#时总会为委托而感到疑惑,但现在总新温习了一遍C语言后,才真正理解的委托. 其实委托就类似于C/C++里的函数指针,在函数传参时传递的是函数指针,在调用 ...
- C语言二重指针与malloc
(内容主要源于网上,只是加入了些自己的剖析) 假设有一个二重指针: char **p; 同时有一个指针数组 char *name[4]; 如何引用p呢? 首先我们有程序代码如下 #include &l ...
- C语言函数指针基础
本文写的非常详细,因为我想为初学者建立一个意识模型,来帮助他们理解函数指针的语法和基础.如果你不讨厌事无巨细,请尽情阅读吧. 函数指针虽然在语法上让人有些迷惑,但不失为一种有趣而强大的工具.本文将从C ...
- 为什么C/C++语言使用指针
这是参加面试时,面试官问的一道开放性题目. 问题是:为什么C/C++语言使用指针? 这个问题一问出来,直接被面试官秒杀了,面试官大神,你怎么不按套路出牌啊? 说好的malloc和new的区别呢?说好的 ...
- C语言的指针变量
C语言的指针变量 在C语言中,变量是固定范围的存储空间,它存储的是赋给他的值, 比如: ; /* 这里是定义一个整型变量a,并把12这个值存储在a的地址空间上 这个地址空间是系统随机分配的,对用户是透 ...
- Android For JNI(五)——C语言多级指针,结构体,联合体,枚举,自定义类型
Android For JNI(五)--C语言多级指针,结构体,联合体,枚举,自定义类型 我们的C已经渐渐的步入正轨了,基础过去之后,就是我们的NDK和JNI实战了 一.多级指针 指针的概念我们在前面 ...
- “对外部(局部)变量的访问”是C语言函数指针的最大弱点
1.“对外部(局部)变量的访问”是C语言函数指针的最大弱点 . #include <stdio.h> #include <stdlib.h> /* 结构体定义 */ struc ...
- go语言学习--指针的理解
Go 的原生数据类型可以分为基本类型和高级类型,基本类型主要包含 string, bool, int 及 float 系列,高级类型包含 struct,array/slice,map,chan, fu ...
- C语言中指针占据内存空间问题
以前一直有个疑问,指向不同类型的指针到底占用的内存空间是多大呢? 这个问题我多次问过老师,老师的答案是"指向不同类型的指针占据的内存空间大小不同",我一直很之一这个答案,今天我就做 ...
随机推荐
- 高德地图的JSAPI学习笔记【一】
高德地图的项目要做 学习笔记记录下来 一.注册账号并申请Key 二.准备页面写好 1.在页面添加 JS API 的入口脚本标签,并将其中「您申请的key值」替换为您刚刚申请的 key: <sc ...
- h5和native测试时的区别
我们以往的APP是使用原生系统内核的,相当于直接在系统上操作,是我们传统意义上的软件,更加稳定 H5的APP先得调用系统的浏览器内核,相当于是在网页中进行操作,较原生APP稳定性稍差,似乎还没有百万级 ...
- ubuntu16.04 共享文件夹之后 /mnt/hgfs目录下没有显示共享的文件夹
root权限执行: apt-get install open-vm-tools vmhgfs-fuse .host:/ /mnt/hgfs
- nginx 配置相关解析
nginx模块处理流程一般是这样的: 客户端发送HTTP请求 –> Nginx基于配置文件中的位置选择一个合适的处理模块 ->(如果有)负载均衡模块选择一台后端服务器 –> 处理模块 ...
- Java错误体系
1.Java所有的异常错误都继承与Throwable类,只有继承了Throwable类,才能在异常传递体系中进行. 2.Throwable下有两个重要的子类,Error和Exception Error ...
- bootm跳转到kernel的流程
转自 https://blog.csdn.net/ooonebook/article/details/53495021 一.bootm说明 bootm这个命令用于启动一个操作系统映像.它会从映像文件的 ...
- redis常用操作(测试必备)
连接redis redis的安装及基础配置,参考:https://www.cnblogs.com/UncleYong/p/9882843.html redis中,数据是key-value方式存储,ke ...
- webpack 的安装与使用
这里使用webpack4.41.2 为例 一.安装webpack 1.本地安装,安装最新版本或特定版本 npm install --save-dev webpack npm install --sav ...
- Browser cannot find PAC because wpad hostname cannot be resolved
Enterprise Network administrator may faultly forget to configure wpad hostname to DNS server. If use ...
- 拷贝插件 copy-webpack-plugin
用于拷贝文件或目录到输出目录中 https://blog.csdn.net/weixin_41643133/article/details/95489335 https://www.jianshu.c ...