Go语言 函数传递:值传递 和 虚假的 “引用传递”

news2024/11/17 8:53:11

前言

  • 其实从变量本身来说,go只有值传递,函数内的修改不会影响函数外。
  • 但有一种特例是指针,go可以传指针给函数,指针指向申请出来的实际内存,也就是保存元素的内存,
    这样在函数内的修改,可以影响到函数外。

分类看一下Go的函数传递:

  1. 基本数据类型int
  2. 类的实例
  3. 数组

基本类型(int)

值传递:

/* 引入单测包 */
import ("testing")

func TestSwap(t *testing.T) {
	x := 100
	y := 200
	swap(x, y)
	println("x:", x)
	println("y:", y)
}

/* 定义相互交换值的函数 */
func swap(x, y int) int {
   var temp int

   temp = x /* 保存 x 的值 */
   x = y    /* 将 y 值赋给 x */
   y = temp /* 将 temp 值赋给 y*/

   return temp;
}

结果:
个人理解:传给swap函数的相当于一个值,swap函数会把形参作为一个局部变量新建,局部变量的修改,不影响原值。
在这里插入图片描述

传递指针

func TestSwap(t *testing.T) {
	x := 100
	y := 200
	swapByPoint(&x, &y)
	println("x:", x)
	println("y:", y)
}

func swapByPoint(x, y *int) int {
	var temp int

	temp = *x /* 保存 x 的值 */
	*x = *y    /* 将 y 值赋给 x */
	*y = temp /* 将 temp 值赋给 y*/

	return temp;
}

结果:函数里面的修改,影响了原值
在这里插入图片描述
个人总结:当传递指针给函数时,类似于传递了内存地址给函数,函数会对这块内存做修改,所以会影响原值。

类的实例

值传递

import (
	"testing"
)

type Person struct{
	Name string
}

func TestChangeName(t *testing.T) {
	person := new(Person)
	person.Name = "aaaaaaa"

	changeName(*person)
	println("name:", person.Name)
}

func changeName(person Person) {
	person.Name = "bbbbbb"
}

结果:未改变原值
在这里插入图片描述

传递指针

func TestChangeName(t *testing.T) {
	person := new(Person)
	person.Name = "aaaaaaa"

	changeName(person)
	println("name:", person.Name)
}

func changeName(person *Person) {
	person.Name = "bbbbbb"
}

结果:影响了原值
在这里插入图片描述
小结:传变量只会被当做局部变量,传指针才会影响原值

Slice(切片)

先上结论:

func test1(slice_2 []int) {
	slice_2[1] = 6666               //函数外的slice确实有被修改
	slice_2 = append(slice_2, 8888) //函数外的不变
}

func test2(slice_2 *[]int) {        //这样才能用APPEND修改函数外的slice
	*slice_2 = append(*slice_2, 6666)
}

原因

  • slice(切片)是一个结构体,这个结构体中有一个指针,指向申请出来的实际内存。
  • 传递slice的时候,这个结构体是值传递的,传递完成后,内存中有两个“slice结构体”,它们引用同一块“slice数组”,第一个例子slice_2[1]是修改这个数组内容,所以里面改了外面能看到改动.
  • append这个函数则根据情况不同有两种工作方式,若你slice的cap足够,则直接修改其引用的数组区域并简单将len增加,并返回这个slice本身,即这时候h=append(h,…)之后,h还是引用原来的数组区域,只不过h的len增加了;若cap不够,则重新申请一块数组区域并将原来的数组内容拷贝过去后再进行追加元素操作,这时候append的返回的slice引用的是另一块内存了

来源链接:https://www.zhihu.com/question/47390706/answer/614694546

附上slice的结构:

// Slice结构体
struct    Slice
{    // must not move anything
    byte*    array;        // actual data
    uintgo    len;        // number of elements
    uintgo    cap;        // allocated number of elements
};

打印一下len和cap(容量),和原因中的解释是一样的:
在这里插入图片描述

总结:

  • Go只有值传递,但可以传递指针

参考文档:
https://www.zhihu.com/question/47390706

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

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

相关文章

就算是TOP程序员,也有这些坏习惯

绝大多数程序员在职业生涯中,多多少少都会养成一些坏习惯,今天就来说一说身边最常见的一些坏习惯,也给刚入行的新朋友们提个醒,少走一些弯路。 那么,就让我们开始吧! 1.不注意适当休息 比如日常工作时、…

B端产品-登录功能设计

在项目启动初期,基本大家都是先从账号体系先开始着手设计的,那么B端的登录功能如何设计呢? 一、需求分析 B端的产品的用户基本上可以分为内部员工和客户,如果是客户使用,基本上都会有注册功能;如果是内部员…

C# Console.Read读取回车和换行

C#的Console.Read函数: 读取缓冲区中的数据,读取到一个字符时停止。 C#的Console.ReadLine函数 读取缓冲区中的数据,遇到回车时停止。 Enter键: 将行数据输入缓冲区,并且将回车符和换行符 加入缓冲区。 注意 Consol…

【H5UI库和二维码】一.H5UI库;二.加密技术;三.二维码

目录​​​​​​​ 一.H5UI库 1.使用方法: (1)页面中引入css文件 (2)页面中引入js文件 2.组件的用法 (2)按钮的使用:button。有三种类型(primary、danger、defaul…

MXNet的Faster R-CNN(基于区域提议网络的实时目标检测)《3》

前面了解到Faster R-CNN在实验中的效果很不错,以及对论文做了一个大概的了解,对此有兴趣的伙伴们也可以先浏览前面两篇文章:MXNet的Faster R-CNN(基于区域提议网络的实时目标检测)《1》MXNet的Faster R-CNN(基于区域提议网络的实时目标检测)《…

【Node】Node.js安装与配置(详细步骤)

Node.js安装与配置(详细步骤)一、安装Node.js1.1 下载1.2 安装1.3 环境变量二、验证是否安装成功三、修改模块下载位置3.1 查看npm默认存放位置3.2 在 nodejs 安装目录下,创建 “node_global” 和 “node_cache” 两个文件夹3.3 修改默认文件…

xd卡数据丢失原因和三种数据恢复方法介绍

xd卡适用于富士/奥林巴斯相机品牌,它能配合各式读卡器,方便的与个人电脑连接传输图像视频等。但是xd卡与其他类型的存储卡一样容易因各种原因出现数据丢失。如果您的xd卡出现了数据丢失的问题,不妨了解下这里给大家分析的xd卡数据丢失原因和具…

解决仓库产品管理痛点,选对条码工具至关重要

" 最近我们仓库管理遇到了很多问题,一方面 我们进出库的产品数量非常庞大,目前公司的条码扫描系统识别效率非常低,只能单个产品进行扫描,经常需要加班加点出入库,而且有些产品条码比较特殊,现在的扫描…

【LeetCode每日一题】——507.完美数

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 数学 二【题目难度】 简单 三【题目编号】 507.完美数 四【题目描述】 对于一个 正整数&…

windows10安装goland

一、安装包 下载以下两个安装包: go语言二进制包: https://golang.google.cn/dl/ goland安装包 https://www.jetbrains.com/go/nextversion/ 二、安装go语言包 双击下载的语言包,直接next,选择安装路径(自己选择&am…

图的遍历(深度DFS与广度BFS)

文章目录图的遍历深度优先遍历思路邻接表邻接矩阵性能分析广度优先遍历思路邻接表邻接矩阵性能分析源代码图的遍历 **对有向图和无向图进行遍历是按照某种次序系统地访问图中的所有顶点, 并且使得每一个顶点只能访问一次. ** 对于图的遍历需要解决掉两个问题: 如果存在回路/环…

实力总结四类Bean注入Spring的方式

xml 方式 注解方式 Configuration Bean Import FactoryBean BDRegistryPostProcessor 源码 实战 一提到Spring,大家最先想到的是啥?是AOP和IOC的两大特性?是Spring中Bean的初始化流程?还是基于Spring的Spring Cloud全家桶呢…

Vue组件之间的通信

1、组件:是vue的重要的特征之一,可以扩展html的功能,也可以封装代码实现重复使用 2、组件的创建 (1)非脚手架方式创建: 1️⃣使用vue.extend创建组件 2️⃣使用vue.component注册组件 3️⃣在html页面…

一个平凡打工人在 CSDN 的 2022 与 2023

平凡又不平凡的一年 2022 年是不平凡的一年,这一年经历了疫情的起起伏伏,随着身边好多同学的毕业离开,手头的工作也愈发的繁重,2022 年也顺理成章的成为了工作3年来最忙碌的一年,但却也是博客产出与自己收获最多的一年…

大数据hadoop和spark怎么选择?

Hadoop框架的主要模块包括如下: Hadoop Common Hadoop分布式文件系统(HDFS) Hadoop YARN Hadoop MapReduce 虽然上述四个模块构成了Hadoop的核心,不过还有其他几个模块。这些模块包括:Ambari、Avro、Cassandra、Hive、 Pig、Oozie、Flume…

spring之静态代理

文章目录前言一、代理模式中的三大角色二、静态代理引入1.业务接口2.目标对象总结前言 在Java程序中代理模式的作用: 当一个对象需要收到保护的时候可以考虑使用代理对象去完成某个行为需要给某个对象的功能进行功能增强的时候,可以考虑找一个代理进行…

Java内存模型(JMM)详解!

文章目录什么是JMM?现代计算机内存模型缓存一致性JMM内存模型与计算机内存模型的关系线程间通信JMM三大问题原子性可见性有序性什么是JMM? JMM定义了Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式。 JMM可以理解为是一个规范,一个抽象概念,并不真实…

Java 单元测试

目录 一、Junit 1.1、单元测试初始化与清理资源 1.2、捕获异常 1.3、条件测试 1.4、标记失效测试方法 1.5、参数化测试 单元测试:是对最小功能单元编写的测试代码。 示例,当开发好一个 Java 阶乘的方法。 n! 1 x 2 x 3 x ..…

CRM软件哪个好?该如何选择?

CRM软件哪个好?该如何选择? CRM是集营销、销售、服务为一体的围绕客户全生命周期管理的系统,在各行各业的数字化转型大潮中,作为以消费者、终端用户、客户为主导的企业经营管理核心系统,CRM选型的难度和复杂度也在不断…

关于ETL的两种架构(ETL架构和ELT架构)

ETL,是英文 Extract-Transform-Load 的缩写,用来描述将数据从来源端经过抽取(extract)、转换(transform)、加载(load)至目的端的过程。ETL一词较常用在数据仓库,但其对象…