go 函数或者方法参数调用的过程

news2024/7/6 18:53:47

前言

最近做项目,使用go开发,但是在发生函数调用传参数时,对指针的指针的传递有难以理解的代码,就此分析过程。尤其是对于多重指针作为参数,而且对于一些内置函数的修改逻辑也需深入的理解。

1. demo

package slice_demo

import (
	"fmt"
	"testing"
)

func TestSliceCall(t *testing.T) {
	s := make([]int, 1, 10)
	fmt.Printf("1.---- %p %p %v\n", &s, s, s)
	a := append(s, 2, 3)
	fmt.Printf("1.---- %p %p %v\n", &a, a, a)
	changeSlice(a)
	changeSlicePoint(&a)
	fmt.Println(a, s)
}

func changeSlice(b []int) {
	b = append(b, 5, 6)
	b[0] = 111
	fmt.Printf("2.---- %p %p %v\n", &b, b, b)
}

func changeSlicePoint(p *[]int) {
	*p = append(*p, 10, 12)
	fmt.Printf("3.---- %p %p %p %v\n", &p, p, *p, p)
}

从demo看,有2种方式传参数修改切片的值,有下标修改,有append修改,结果有点出乎我们日常逻辑,结果如下

=== RUN   TestSliceCall
1.---- 0xc000118090 0xc000154140 [0]
1.---- 0xc0001180d8 0xc000154140 [0 2 3]
2.---- 0xc000118120 0xc000154140 [111 2 3 5 6]
3.---- 0xc000100028 0xc0001180d8 0xc000154140 &[111 2 3 10 12]
[111 2 3 10 12] [111]
--- PASS: TestSliceCall (0.00s)
PASS

可以看到append后的指针跟append前的切片是一样的,切片本身是引用类型,实现逻辑是数组,且是同一个数组(没扩容,且内存地址一样),但是值不一样。

而且切片在传入函数参数后,通过append并没有修改 传入的参数切片引用,可以通过下标修改;但是通过切片指针通过append却可以修改,原理是什么😅

 

2. 分析

2.1 先分析append的情况

结合这2行打印分析,append的过程

可以看到创建了2个变量(栈的引用) ,所以分配了2个内存地址,同时指向同一个数组(因为切片本身是指针),然而s和a的值却不一样。那么这是什么原因?实际上数组的内存地址仅仅是数组开始的内存地址,数组是连续的内存空间,是一个初始地址+offset或者position定位。看slice结构体可以明白,实际上内存地址后面的值已经被改掉了。

2.2 slice的结构体

type slice struct {
	array unsafe.Pointer
	len   int
	cap   int
}

slice.go定义了结构体,实际上slice是数组指针与len cap组成的,slice的扩容就是创建复制数组 ,修改len和cap。

2.3 slice直接传入函数参数

实际上append未生效,并不是未生效,已经修改了数组后面的连续内存的值了,只是因为没有对原始的变量赋值,没有修改len与cap,因为切片的结构体slice是基本数据类型,内存拷贝,是2个结构体,所以读取值是没变的。

分析原理画成图,跟实际结果符合。

 

 

2.4 slice传入函数指针

实际上切片没必要使用指针,因为切片本身就是指针,很多教程也推荐切片不使用指针,直接用;但是指针却有特殊的意义,可以修改传入的参数的数据值。

 

因为传入的切片的指针,所以p可以认为是a,因为是a的指针内存地址,操作a的指针内存地址就等于操作变量a,所以对*p赋值,可以修改a的值。

2.5 切片操作相互影响 

 因为切片的实现是数组,因为是指针,所以变量的修改会相互影响。这个就很容易理解了

总结

这里的问题是切片本身是指针,如果再加入指针,就是指针的指针,很难理解。而且再结合函数的参数,本身函数的参数是一个引用,栈变量自己又会分配内存地址,就更难理解了😅。这里的关键还有切片是一个结构体存储的,但是结构体又是内存值拷贝,而非内存地址引用。实际上可以结合内存分配的流程结合函数的入栈出栈,外加参数的存储结构很容易就明白原理了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/168868.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

client-go源码学习(四):自定义Controller的工作原理、WorkQueue

本文基于Kubernetes v1.22.4版本进行源码学习,对应的client-go版本为v0.22.4 4、自定义Controller的工作原理 Controller中主要使用到Informer和WorkQueue两个核心组件 Controller可以有一个或多个Informer来跟踪某一个resource。Informer跟Kubernetes API Server保…

安装 Visual Studio Code、MinGW-w64、CMake

文章目录1.安装 Visual Studio Code1.1 下载1.2 安装2.安装 MinGW-w642.1 下载2.2 解压到合适的目录下2.3 添加到环境变量2.4 测试是否安装成功3.安装 CMake3.1 下载3.2 解压到合适的目录下3.3 添加到环境变量3.4 测试是否安装成功1.安装 Visual Studio Code 1.1 下载 Visual…

Options API

computed计算属性 1、复杂data的处理方式 我们知道,在模板中可以直接通过插值语法显示一些data中的数据。 但是在某些情况,我们可能需要对数据进行一些转化后再显示,或者需要将多个数据结合起来进行显示; 比如我们需要对多个d…

自动驾驶控制算法之车辆纵向控制(project)

本文为深蓝学院-自动驾驶控制与规划-第二章作业 目录 1 project introduction 2 思路提示 3 解决积分饱和的方法 3.1 IC 积分遇限削弱法 3.2 BC 反馈抑制抗饱和 4 ROSLGSVL联合仿真 1 project introduction 本项目希望大家根据PID控制方法实现一个巡航控制系统。我们已…

深度学习之边缘检测算法论文解读(EDTER: Edge Detection with Transformer)

引言 边缘检测是计算机视觉中最基本的问题之一,具有广泛的应用,例如图像分割[8,23,39,44,45,47]、对象检测[23]和视频对象分割[5,57,59]。给定输入图像,边缘…

webpack-dev-server:静态资源目录配置

目录 webpack-dev-server Webpack项目-配置自动打包 访问错误信息分析 简单配置静态资源访问目录 完整配置静态资源访问目录 directory属性 staticOptions属性 publicPath属性 serveIndex属性 watch属性 完整配置webpack.config.js示例 默认显示index.html内容配置 默…

fsdb DUMP的操作记录

参考链接: https://blog.csdn.net/ohuo666/article/details/124973939https://blog.csdn.net/ohuo666/article/details/124973939 https://blog.csdn.net/yuexiangallan/article/details/121760768https://blog.csdn.net/yuexiangallan/article/details/121760768…

基于 DolphinDB 的行情中心解决方案

随着国内量化金融的高速发展,行情数据所包含的微观交易结构信息越来越受到券商自营团队、资管团队以及各类基金的重视。这些交易团队迫切希望拥有一个与生产环境类似的投研仿真环境,提升研发的效率和质量。作为国内领先的高性能时序数据库厂商&#xff0…

【地铁上的Redis与C#】数据类型(七)--List类型

我们这篇文章开始讲解list类型。 什么是list list是一个存储空间保存多个数据,底层使用双向链表存储结构实现的一种Redis数据类型,。list类型一般用在存储多个数据,并需要对数据进入存储空间的顺序进行区分的情况下。list的存储方式是一个存…

气泡法检漏技术特点分析和新型压力衰减法测试技术

摘要:针对传统的气泡法检漏技术,本文详细介绍了气泡法的基本原理、气泡法中的两种标准方法——加压法和真空法以及对应的标准规范,并对这两种气泡法进行了对比分析。本文还对气泡法的技术特点进行了分析,指出了气泡法检漏技术的局…

使用ruoyi-vue控制数据权限

说在前面 啥是数据权限?例如校长可以看到全部学生的信息,系主任可以看到该院系的学生信息,老师可以看到本班的学生信息,学生自己只能查看自己的信息 对于ruoyi的角色,我们只能控制用户可以访问那些菜单以及接口,而不能控制接口返回的数据 假如有这样一个需求,不同用户上传各…

赛狐ERP | 亚马逊卖家FBA常见问题解析!

许多亚马逊卖家在使用亚马逊FBA时经常会遇到一些问题,如FBA如何收费、如何提升发货数量、物流方式问题等问题,这些问题是常见问题,也是亚马逊卖方们应该把握的问题。下面就来跟大家分享一些常见的亚马逊FBA相关问题。一、亚马逊FBA如何收费&a…

OSCP_vulnhub—GOLDENEYE: 1

vulnhub—GOLDENEYE: 1About信息搜集查看js泄露POP3 密码破解及登录使用admin/xWinter1995x!登录 getshell提权About GoldenEye: 1 ~ VulnHub Download (Mirror): https://download.vulnhub.com/goldeneye/GoldenEye-v1.ova DHCP service: Enabled IP address: Automaticall…

【Kubernetes 入门实战课】Day01——虚拟机创建及安装

文章目录前言一、实验环境选择二、选择合适的虚拟机软件1.VirtualBox2.VMWare三、Linux版本四、如何配置虚拟机1、安装VMware2、虚拟网络设置1、虚拟机网络编辑器2、设置 VMnet 8 网段3、创建虚拟机1、创建虚拟机2、启动虚拟机3、虚拟机配置4、虚拟机管理前言 俗话说&#xff…

[oeasy]python0052_ raw格式字符串_单引号_双引号_反引号_ 退格键

转义字符 回忆上次内容 最近玩的是\n、\r 之外的转义序列 \a是 ␇ (bell)\t是 水平制表符\v是 换行不回车 通过 16 进制数值转义 \xhh把(hh)16 进制对应的 ascii 字符输出 通过 8 进制数值转义 \ooo把(nnn)8 进制对应的 ascii 字符输出 这次加了 转义输出 反斜杠本身 \\ 输出…

24.Isaac教程--路径规划的区域划分

路径规划的区域划分 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 为了赋予地图区域关于通过它们规划的路径的语义意义,引入了三个新的规划器影响区域: No-replanning zones:当机器人通过这个多边形区域时&a…

python textwrap 模块,这里有你需要的学习资料

Python 标准库中的 textwrap 模块可以把长文本按照指定的宽度进行换行。这个模块提供了一些高级的文本处理功能,例如按照指定的宽度进行自动换行,保留段首缩进等。 python textwrap 模块python textwrap 模块主要函数textwrap.wrap(text, width70, \*\*k…

ruoyi-vue版本(四)@PreAuthorize 注解在若依里面的作用,springsecurity 框架相关的配置

目录1 需求2 实现2.1 背景2.2 实现2.3 springsecurity 框架相关的配置2.3.1 EnableGlobalMethodSecurity详解2.3.2 认证失败处理类AuthenticationEntryPointImpl2.3.3 自定义退出处理类LogoutSuccessHandlerImpl2.3.4 filter 为啥会多次执行3 PreAuthorize 注解1 需求 我们打开…

Flink面试题汇总

1,简单介绍一下 Flink Flink 是一个框架和分布式处理引擎,用于对无界和有界数据流进行有状态计算。并且 Flink 提供了数据分布、容错机制以及资源管理等核心功能。Flink提供了诸多高抽象层的API以便用户编写分布式任务: DataSet API&#xf…

nacos多网卡服务器引发的问题

1、背景 某一日晚上,公司的一个微服务上线重启后,双节点,只有一个节点注册到了nacos服务器,另外一个节点一直在nacos界面上无法看到,两个节点的服务启动也没有报错,api网关转发给服务时,时不时有…