Go语言:参数传递中,值、引用及指针之间的区别

简介: 1、在Go语言中,值类型和引用类型有以下特点:a、值类型:基本数据类型,int,float,bool,string,以及数组和struct 特点:变量直接存储值,内存通常在栈上分配,栈在函数调用完会被释放

值类型、引用类型

1、在Go语言中,值类型和引用类型有以下特点:

a、值类型:基本数据类型,int,float,bool,string,以及数组和struct 特点:变量直接存储值,内存通常在栈上分配,栈在函数调用完会被释放

b、引用类型:指针,slice,map,chan,interface等都是引用类型 特点:变量存储的是一个地址,这个地址存储最终的值。内存通常在堆上分配,通过GC回收。

  • 严格来说,Go 语言没有引用类型。
  • 但是我们可以把 map、chan、函数、接口、slice 切片, 称为引用类型,这样便于理解。
  • 指针类型也可以理解为是一种引用类型。

上面我们提到了堆、栈,这里简单介绍下

内存分配中的堆和栈:

  • (操作系统):由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
  • (操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。

值类型和指针类型参数示例:

package main
import "fmt"
func main() {
  name := "无尘"
  modify1(name)
  fmt.Println("name的值为:", name)
  modify2(&name)
  fmt.Println("name的值为:", name)
}
func modify1(name string) { //值类型
  name = "wucs"
} 
func modify2(name *string) { //指针类型
  *name = "wucs"
}
//运行结果:
//name的值为: 无尘
//name的值为: wucs
复制代码

引用类型

map以map类型为参数示例:

package main
import "fmt"
func main() {
  m:=make(map[string]int)
  m["无尘"] = 18
  fmt.Println("无尘的年龄为",m["无尘"])
  modify(m)
  fmt.Println("无尘的年龄为",m["无尘"])
}
func modify(p map[string]int)  {
  p["无尘"] =20
}
//运行结果:
//无尘的年龄为 18
//无尘的年龄为 20
复制代码
  • 我们看到,函数 modify 的参数类型为 map ,数据仍然修改成功了。
  • 其实,在创建 map 的时候,最终调用的是 runtime.makemap 函数,makemap 函数返回的是一个 *hmap 类型,也就是说返回的是一个指针,所以我们创建的 map 其实就是一个 *hmap。
  • 因为 map 本质上就是个指针,所以通过 map 类型的参数可以修改原始数据。
// makemap implements Go map creation for make(map[k]v, hint).
func makemap(t *maptype, hint int, h *hmap) *hmap{
  //省略无关代码
}
复制代码

chanchannel 本质上也是个指针,来看源码:

func makechan(t *chantype, size int64) *hchan {
    //省略无关代码
}
复制代码

可以看到创建的 chan 其实是个 *hchan,所以它在参数传递中也和 map 一样。

类型的零值

  1. 在 Go 语言中,定义变量可以通过声明或者通过 makenew函数,区别是 make 和 new 函数属于显示声明并初始化。
  2. 如果我们声明的变量没有显示的声明初始化,那么该变量的默认值就是对于类型的零值。
类型 零值
数值类型(int、float等) 0
bool false
string ""(空字符串)
struct 内部字段的零值
slice nil
map nil
指针 nil
函数 nil
chan nil
interface nil

在 Go 语言中,函数的参数传递只有值传递,而且传递的实参都是原始数据的一份拷贝。如果拷贝的内容是值类型的,那么在函数中就无法修改原始数据;如果拷贝的内容是指针(或者可以理解为引用类型 map、chan 等),那么就可以在函数中修改原始数据。

相关文章
|
6天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
23 2
|
5天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
13 2
|
5天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
16 2
|
5天前
|
Go
go语言中的 跳转语句
【11月更文挑战第4天】
13 4
|
5天前
|
JSON 安全 Go
Go语言中使用JWT鉴权、Token刷新完整示例,拿去直接用!
本文介绍了如何在 Go 语言中使用 Gin 框架实现 JWT 用户认证和安全保护。JWT(JSON Web Token)是一种轻量、高效的认证与授权解决方案,特别适合微服务架构。文章详细讲解了 JWT 的基本概念、结构以及如何在 Gin 中生成、解析和刷新 JWT。通过示例代码,展示了如何在实际项目中应用 JWT,确保用户身份验证和数据安全。完整代码可在 GitHub 仓库中查看。
18 1
|
11天前
|
JavaScript Java Go
探索Go语言在微服务架构中的优势
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出。本文将深入探讨Go语言在构建微服务时的性能优势,包括其在内存管理、网络编程、并发模型以及工具链支持方面的特点。通过对比其他流行语言,我们将揭示Go语言如何成为微服务架构中的一股清流。
102 53
|
10天前
|
Ubuntu 编译器 Linux
go语言中SQLite3驱动安装
【11月更文挑战第2天】
31 7
|
10天前
|
关系型数据库 Go 网络安全
go语言中PostgreSQL驱动安装
【11月更文挑战第2天】
39 5
|
9天前
|
安全 Go
用 Zap 轻松搞定 Go 语言中的结构化日志
在现代应用程序开发中,日志记录至关重要。Go 语言中有许多日志库,而 Zap 因其高性能和灵活性脱颖而出。本文详细介绍如何在 Go 项目中使用 Zap 进行结构化日志记录,并展示如何定制日志输出,满足生产环境需求。通过基础示例、SugaredLogger 的便捷使用以及自定义日志配置,帮助你在实际开发中高效管理日志。
26 1
|
9天前
|
程序员 Go
go语言中的控制结构
【11月更文挑战第3天】
85 58