go语言中的函数详解

news2024/10/12 3:16:00

1. 引言

函数是编程中不可或缺的组成部分,无论是在Go语言还是其他编程语言中,函数都扮演着重要的角色。函数能够将一系列的操作封装在一起,使得代码更加模块化、可重用和易于维护。

在本文中,我们将详细介绍Go语言中函数的概念和使用方法,包括函数的定义、参数和返回值、调用方式、可变参数、函数作为参数和返回值等方面的内容。

2. 函数的基本定义

在Go语言中,定义函数需要按照以下语法:

func functionName(parameter1 type1, parameter2 type2) returnType {
    // 函数体
    // 可以包含一系列的语句和操作
    return value // 返回值(如果有)
}

其中,各个部分的含义如下:

  • func: 关键字用于定义函数。
  • functionName: 函数名,用于唯一标识该函数。
  • parameter1, parameter2: 参数列表,函数可以接收零个或多个参数。每个参数由参数名和参数类型组成,多个参数之间使用逗号分隔。
  • type1, type2: 参数的类型,指定参数的数据类型。
  • returnType: 返回类型,指定函数的返回值的数据类型。如果函数没有返回值,则返回类型为空。
  • return value: 可选项,用于返回函数的结果。如果函数定义了返回类型,则需要使用return语句将结果返回给调用者。

下面是一个示例函数的定义:

func add(a int, b int) int {
    sum := a + b
    return sum
}

上述示例中,函数名为add,接收两个参数ab,类型为int,并且返回类型也为int。函数体内部计算参数的和,并将结果使用return语句返回。

3.1 值传递

传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。

以下定义了 swap() 函数:

package main

import "fmt"

func main() {
	/* 定义局部变量 */
	var a int = 100
	var b int = 200

	fmt.Printf("交换前 a 的值为 : %d\n", a)
	fmt.Printf("交换前 b 的值为 : %d\n", b)

	/* 通过调用函数来交换值 */
	swap(a, b)

	fmt.Printf("交换后 a 的值 : %d\n", a)
	fmt.Printf("交换后 b 的值 : %d\n", b)
}

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

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

	return temp
}

运行结果:

交换前 a 的值为 : 100
交换前 b 的值为 : 200
交换后 a 的值 : 100
交换后 b 的值 : 200

可见交换前后a,b的值没变。
所以值传递不会改变所传入实参的值。只是复制一份值用于函数体执行而已。

3.2 引用参数

引用参数是通过将参数的地址传递给函数来进行传递的。这样函数就可以通过指针来间接地修改原始数据。因为传递指针只需要占用较小的内存,所以其通常适用于需要修改原始数据或者数据量较大的场景。下面通过一个切片的例子来进行说明,切片内部保存了数组的指针,可以认为是传递了数组引用:

func appendValue(slice []int, value int) {
    slice = append(slice, value)
    fmt.Println("Inside appendValue function:", slice)
}

func main() {
    numbers := []int{1, 2, 3}
    appendValue(numbers, 4)
    fmt.Println("After function call:", numbers)
}

输出结果为:

Inside appendValue function: [1 2 3 4]
After function call: [1 2 3 4]

在上述示例中,appendValue函数接收一个切片作为引用参数slice,并在函数内部使用append函数向切片中追加一个值。这个修改会影响到原始的numbers切片。

所以如果函数内想要修改参数值,此时可以通过传递引用参数来达到这个目的。

(2)引用传递

引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

引用传递将指针参数传递到函数内,以下是交换函数 swap() 使用了引用传递:

package main

import "fmt"

func main() {
	var a int = 100
	var b int = 200

	fmt.Printf("交换前a的值为:%d\n", a)
	fmt.Printf("交换前b的值为:%d\n", b)

	/* 调用 swap() 函数
	 * &a 指向 a 指针,a 变量的地址
	 * &b 指向 b 指针,b 变量的地址
	 */
	swap(&a, &b)
	fmt.Printf("交换后,a 的值 : %d\n", a)
	fmt.Printf("交换后,b 的值 : %d\n", b)
}

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

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

	return temp
}

输出结果:

交换前,a 的值 : 100
交换前,b 的值 : 200
交换后,a 的值 : 200
交换后,b 的值 : 100

 注意:

  1. 无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。
  2. map、slice、chan、指针、interface默认以引用的方式传递。

3.3 可变参数

Go语言支持可变参数函数,即函数可以接受可变数量的参数。在Go语言中,可变参数函数使用 ... 操作符来表示。该操作符放置在参数类型前面,用于指示该参数可以接受多个值。具体语法如下:

func myfunc(args ...int) {    //0个或多个参数
}

func add(a int, args…int) int {    //1个或多个参数
}

func add(a int, b int, args…int) int {    //2个或多个参数
}

其中,param 是可变参数的名称,Type 是可变参数的类型。在函数体内,我们可以像处理切片一样处理可变参数,使用循环或索引来遍历和访问参数的值。下面是一个使用可变参数函数的示例:

func sum(numbers ...int) int {
    total := 0
    for _, num := range numbers {
        total += num
    }
    return total
}

func main() {
    result := sum(1, 2, 3, 4, 5)
    fmt.Println("Sum:", result)
}

在上述示例中,sum 函数使用可变参数 numbers 来接收多个整数值。在函数体内,我们使用循环遍历 numbers 切片,并累加每个整数值到 total 变量中。最后,函数返回累加的总和。

实例 2:使用切片赋值

在参数赋值时可以不用一个一个的赋值,可以直接传递一个数组或者切片,特别注意的是在参数后加上“”即可。

使用 slice 对象做变参时,必须展开。(slice…)

import (
	"fmt"
)

func test(s string, n ...int) string {
	var x int
	for _, i := range n {
		x += i
	}
	return fmt.Sprintf(s, x)
}

func main() {
	s :=[] int{1,2,3}
	res :=test("sum: %d",s...)
	println(res)
}

 4、函数返回值

  1. 返回值的忽略
    _标识符,用来忽略函数的某个返回值。
    Golang返回值不能用容器对象接收多返回值。只能用多个变量,或 “_” 忽略。

  2. 多返回值可直接作为其他函数调用实参。

package main

func test() (int, int) {
	return 1, 2
}
func add(x, y int) int {
	return x + y
}
func sum(n ...int) int {
	var x int
	for _, i := range n {
		x += i
	}
	return x
}

func main() {
	println(add(test()))
	println(sum(test()))
}

运行结果:

3
3

3.命名返回值

Go 函数的返回值可以被命名,就像在函数体开头声明变量。
返回值的名称应当具有一定的意义,可以作为文档使用。
命名返回参数可看做与形参类似的局部变量,最后由 return 隐式返回。

package main

func add(x, y int) (z int) {
	{ // 不能在一个级别,引发 "z redeclared in this block" 错误。
		 z = x + y
		// return   // Error: z is shadowed during return
		return  // 必须显式返回。
	}
}
func main() {
	println(add(1, 2))
}

注意:命名返回参数可被同名局部变量遮蔽,此时需要显式返回。

package main

func add(x, y int) (z int) {
	{ // 不能在一个级别,引发 "z redeclared in this block" 错误。
		z = x + y
		// return   // Error: z is shadowed during return
		return z // 必须显式返回。
	}
}
func main() {
	println(add(1, 2))
}

4.没有参数的 return 语句返回各个返回变量的当前值。这种用法被称作“裸”返回。
直接返回语句仅应当用在像下面这样的短函数中。
在长的函数中它们会影响代码的可读性。

package main

import "fmt"

func add(a, b int) (c int) {
	c = a + b
	return
}

func calc(a, b int) (sum int, avg int) {
	sum = a + b
	avg = (a + b) / 2
	return
}
func main() {
	var a, b int = 1, 2
	c := add(a, b)
	sum, avg := calc(a, b)
	fmt.Println(c, sum, avg)
}

运行结果:

3 3 1

在 Go 语言中,函数是一等公民,这意味着函数可以作为参数传递给其他函数,也可以作为返回值返回。以下是一些函数作为实参的例子:

实例1:传递函数作为参数

package main

import "fmt"

// 定义一个函数,它来接受一个函数作为参数
func applyFunction(x int, y func(int) int) int {
	return y(x)
}

// 定义一个简单的函数,用于增加
func addFive(x int) int {
	return x + 5
}
func main() {
	result := applyFunction((10), addFive)
	fmt.Println(result)//输出:15
}

实例2:使用匿名函数

在 Go 语言中,匿名函数(也称为立即执行函数或 lambda 表达式)是一种没有名称的函数,通常用于需要函数作为参数的场合。匿名函数可以在定义它们的代码块内立即使用,也可以作为参数传递给其他函数。

package main

import "fmt"
//applyFunction接受一个函数作为参数,并使用这个函数处理输入值
func applyFunction(x int, f func(int) int) int {
	return f(x)
}
func main() {
	//定义并传递一个匿名函数
	result := applyFunction(10, func(x int) int {
		return x * 2
	})
	fmt.Println(result)//输出:20
}

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

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

相关文章

10月更新|国内可用的ChatGPT攻略镜像中文网站

一、GPT中文镜像站 ① yixiaai.com 支持GPT4、4o以及o1,支持MJ绘画 ② chat.lify.vip 支持通用全模型,支持文件读取、插件、绘画、AIPPT ③ AI Chat支持GPT3.5/4,4o以及MJ绘画 1. 什么是镜像站 镜像站(Mirror Site&#xff0…

【GO基础学习】环境安装到基础语法(1)

文章目录 环境安装GoLand 安装GO基础GO特点类型和函数Init函数和main函数GO命令下划线变量和常量数组切片Slice 引用 环境安装 下载地址:https://www.golangroadmap.com/ 安装目录文件说明: api:每个版本的 api 变更差异。 bin&#xff1…

JAVA 字符串 trim() 方法的正确使用

JAVA类里面 trim() 方法大家都比较熟悉,就是用来清除掉字符串首尾的空白字符。但在一次程序运行崩溃后,查找具体原因时,发现是由字符串末尾的一个回车符号 "\r" 所导致的。于是有机会仔细读了下该方法的 java 文档说明。其中一段内…

Docker理念

1.为什么会出现Docker Docker 的出现并非偶然,而是由一系列技术发展趋势和实际需求所推动的一项技术创新。 随着软件行业的快速发展,开发团队的规模不断扩大,成员可能分布在不同的地理位置,使用不同的操作系统和开发工具。这就导致…

CSD(computational storage devices)架构介绍

CSD(computational storage devices)架构介绍 前言一、CSD与传统SSD的架构对比二、为什么要采用FPGA三、FPGA缺点四、个人总结reference 前言 虽然一直有接触CSD,但一直对其原理和架构知之甚少,半知不解。今天,趁着我还…

element-ui点击文字查看图片预览功能

今天做一个点击文字查看图片的功能&#xff0c;大体页面长这样子&#xff0c;点击查看显示对应的图片 引入el-image-viewer&#xff0c;点击的文字时候设置图片预览组件显示并传入图片的地址 关键代码 <el-link v-if"scope.row.fileList.length > 0" type&…

模型预测控制工具包——ACADO:简介、安装与测试

模型预测控制工具包——ACADO&#xff1a;简介、安装与测试 ACADO 工具包简介ubuntu20.04 安装 ACADO工具包安装依赖安装ACADOtoolkit 测试 ACADO 工具包简介 ACADO Toolkit 是一个用 C 编写的用于自动控制和动态优化的软件环境和算法集合。 它提供了一个通用框架&#xff0c;…

三菱FX3UPLC定位控制程序举例

测试程序的编写 1.输入输出的分配输入输出的分配如下表所示。 2、相关软元件的设定 相关软元件也有所不同。更改定位指令的脉冲输出端时&#xff0c;根因设定为定位指令的脉冲输出端的软元件不同&#xff0c;据更改的内容&#xff0c;需要变更设定的相关软元件。 3.程…

【大模型新书】掌握大语言模型:高级技术、应用、尖端方法和顶尖LLMs

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/93e5a5c008474f72a0335083ef9c4893.png)我已将 这本大模型书籍免费分享 出来&#xff0c;需要的小伙伴可以扫取。 主要特性 探索自然语言处理&#xff08;NLP&#xff09;基础和大语言模型基本原理&#xff0c;包括…

若依前端后打成一个JAR包部署

客户需要将项目前后端作为一个整体打包成jar&#xff0c;不使用nginx方式转发。使用框架是若依前后端分离&#xff0c;后端springboot&#xff0c;前端vue&#xff0c;目的就是把vue打入jar。 一、前端修改 ruoyi-ui/src/router/index.js文件 &#xff0c;将 mode: ‘history’…

一键生成二维码的源码系统 电脑+手机版自适应代码 带完整的安装代码包以及搭建部署教程

系统概述 一键生成二维码的源码系统是一款集二维码生成、管理和应用于一体的综合性平台。它采用先进的技术和算法&#xff0c;能够快速、准确地生成各种类型的二维码&#xff0c;包括文本、链接、图片等。同时&#xff0c;该系统还具备高度的灵活性和可扩展性&#xff0c;能够…

如何使用bpmn-js实现可视化流程管理

介绍 BPMN-JS是一个流行的开源库&#xff0c;用于在Web应用程序中可视化、创建、编辑和分析BPMN&#xff08;Business Process Model and Notation&#xff0c;业务流程建模与表示法&#xff09;2.0 图。BPMN是一种国际标准的图形化语言&#xff0c;用于描述企业中的业务流程&a…

mongodb 连接, 去重,索引

mongodb 去重,索引 MongoDB Community Server 下载: https://www.mongodb.com/try/download/community GUI: The Ultimate Client, IDE and GUI for MongoDB | Studio 3T 连接 设置允许远程(局域网)连接 (windows) 在打开文件 "<你的安装目录>\MongoDB\Server\…

k3s安装指定版本以及离线安装(docker)

首先下载你所需要版本的k3s安装包&#xff0c;目录结构如下所示&#xff0c;我这里是v1.19.15k3s2。 1.首先赋予可执行权限后进行安装。 # k3s 需要赋予可执行权限 sudo chmod x k3s sudo chmod x k3s-install.sh2.然后将k3s的二进制文件复制到/usr/local/bin/ cp k3s /us…

✨机器学习笔记(七)—— 交叉验证、偏差和方差、学习曲线、数据增强、迁移学习、精确率和召回率

机器学习笔记&#xff08;七&#xff09; 1️⃣评估模型&#x1f397;️使用测试集评估模型&#x1f397;️交叉验证集&#xff08;cross validation&#xff09; 2️⃣偏差和方差&#xff08;Bias / Variance&#xff09;3️⃣学习曲线&#xff08;Learning curves&#xff09…

自动化分析背后,一站式数据分析平台!

自动化分析背后&#xff0c;一站式数据分析平台&#xff01; 前言一站式数据分析平台 前言 在如今的企业管理中&#xff0c;数据已经不再是简单的存储和备份&#xff0c;而是成为了决策的核心驱动力。尤其是在面对海量数据的情况下&#xff0c;企业急需一个能够高效处理、分析…

学习笔记之指针进阶(10.11)

a[0]就相当于数组名arr&#xff0c;a[0]1就相当于arr1&#xff0c;arr1是数组中下一个元素的地址&#xff0c;所以a[0]1就是数组中下一个元素的地址&#xff0c;&#xff08;把二维数组中的每一个数组看作一个元素&#xff09; 以上解释是错误的&#xff0c;a[0]不是整个数组的…

Leetcode——数组:移除元素—27.移除元素

知识点 双指针&#xff0c;在设置时&#xff0c;设置两个指针&#xff0c;一个用来寻找目标值&#xff0c;一个用来表示新数组的下标。 当找到不是目标值的元素时&#xff0c;将其添加到新数组中&#xff0c;如果是目标值&#xff0c;直接掠过 寻找目标值的指针会遍历整个数…

从commit校验失效问题探究husky原理

一、背景 之前创建的项目&#xff0c;发现代码 commit 提交的时候没有了任何校验&#xff0c;具体表现&#xff1a; 一是 feat fix 等主题格式校验没有了二是代码 lint 不通过也能提交 尝试解决这个问题&#xff0c;并深入了解husky的实现原理&#xff0c;将相关的一些知识点…

Excalidraw:在线手绘风格白板、图表绘制工具

嗨&#xff0c;大家好&#xff0c;我是小华同学&#xff0c;关注我们获得“最新、最全、最优质”开源项目和高效工作学习方法 Excalidraw 是一个开源的虚拟白板&#xff0c;用于绘制手绘风格的图表、线框图等。它支持多人实时协作&#xff0c;并使用端到端加密&#xff0c;确保…