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 等),那么就可以在函数中修改原始数据。

相关文章
|
7月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
375 2
|
9月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
579 0
|
9月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
405 0
|
9月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
453 0
|
9月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
504 0
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
9月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
569 1
|
11月前
|
开发框架 JSON 中间件
Go语言Web开发框架实践:路由、中间件、参数校验
Gin框架以其极简风格、强大路由管理、灵活中间件机制及参数绑定校验系统著称。本文详解其核心功能:1) 路由管理,支持分组与路径参数;2) 中间件机制,实现全局与局部控制;3) 参数绑定,涵盖多种来源;4) 结构体绑定与字段校验,确保数据合法性;5) 自定义校验器扩展功能;6) 统一错误处理提升用户体验。Gin以清晰模块化、流程可控及自动化校验等优势,成为开发者的优选工具。
|
11月前
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。