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语言中指针占据内存空间问题
以前一直有个疑问,指向不同类型的指针到底占用的内存空间是多大呢? 这个问题我多次问过老师,老师的答案是"指向不同类型的指针占据的内存空间大小不同",我一直很之一这个答案,今天我就做 ...
随机推荐
- Docker 的操作命令记录
docker ps:列出正在运行的 container docker ps -a:列出所有的 container docker rm [containerid]:移除 container(可并列多个, ...
- Vue递归组件实现层层嵌套显示数据
问题来自朋友...记录一下 需求是表格头部后端返回的数据中是不确定的 n维数据,表头存在于 listVo 字段中,如何实现层层显示呢? 温馨提示,以下内容为5张大图,请打开 WIFI 享用... 以下 ...
- 微信小程序开发--flex详细解读
一.结构:flex布局 是由一个大的容器加上多个子元素组成. <view class="container"> <view </view> <v ...
- Java集合目录
java集合学习(1):集合框架 java集合学习(2):Map和HashMap Java集合学习(4):HashTable Java集合学习(5):LinkedHashMap Java集合学习(6) ...
- pgsql主备搭建及切换
二.主从搭建 2.1测试目标 测试postgresql主从搭建安装过程 2.2环境准备 实例级别的复制 流复制主库可读写,但从库只允许查询不允许写人, 而逻辑复制的从库可读写 流复制实验环境 主机 主 ...
- 06. redis cluster
目录 Redis Cluster redis cluster 特点 搭建redis cluster 访问redis cluster redis-cli 访问redis cluster 重新分片数据 新 ...
- 海思3519A 移植ffmpeg
文件下载 下载x264 git clone git://git.videolan.org/x264.git 下载ffmpeg git clone git://source.ffmpeg.org/ffm ...
- HTTP中分块编码(Transfer-Encoding: chunked)
转自: 妙音天女--分块传输编码~ 参考链接: HTTP MDN--HTTP协议 一.背景: 持续连接的问题:对于非持续连接,浏览器可以通过连接是否关闭来界定请求或响应实体的边界:而对于持续连接,这种 ...
- 大数据技术原理与应用【第五讲】NoSQL数据库:5.5 从NoSQL到NewSQL数据库
应用场景: OldSql数据库:希望一种架构就能支持多种应用场景,但证明不可能. NewSql数据库:同时具备OldSql和NoSQL各自的优点:水平可扩展性,强一致性,事务一致性,支持查询,支持 ...
- Websocket --socket.io的用法
<!DOCTYPE html> <html> <head> <title>Hello WebSocket</title> <link ...