Go语言学习Day4:函数(上)

名人说:莫愁千里路,自有到来风。 ——钱珝
创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)

目录

      • 1、函数的概念与定义
        • ①函数的概念
        • ②函数的具体定义
        • ③多返回值
      • 2、函数参数与作用域
        • ①可变参数
        • ②形式参数与实际参数
        • ③参数的传递细节
        • ④函数作用域
        • ⑤递归函数
      • 3、小结

1、函数的概念与定义

①函数的概念

在Go语言中,函数是基本的代码块,用于执行一个任务。函数可以接受输入参数,并且可以返回一个或多个值。它们是组织和复用代码的基本单位。在Go中,函数也可以被当作变量,传递给其他函数,或者从其他函数返回。

②函数的具体定义

函数的定义包括函数名、参数列表、返回值列表和函数体。格式如下:

//func 函数名 (参数1 类型1,参数2 类型2...)(返回值类型)
func functionName(param1 type1, param2 type2) (returnType) {// 函数体
}

案例1:自定义sub函数,并通过样例测试

//创作者:Code_流苏(CSDN)
package mainimport "fmt"func sub(x int, y int) int {return x - y
}func main() {result := sub(6, 5)fmt.Println("6 - 5 =", result)
}

image-20240326223222601

案例2:加法,函数调用探析

package mainimport "fmt"/*
函数是基本的代码块,用于执行一个任务
*/
//main()主函数 程序的入口
func main() {var x intvar y intvar z intfmt.Println("请输入x和y的值:")fmt.Scanf("%d%d", &x, &y)//调用函数 函数名()z = add(x, y)fmt.Println(z)
}//函数格式
//func 函数名(参数1,参数2...,参数类型) 返回值类型 {
//  函数体
//  return 返回值
//}func add(a, b int) int {c := a + breturn c
}

image-20240326223332933

③多返回值

Go语言支持函数返回多个值,这在处理错误或者需要返回多种数据时非常有用。

案例1:交换打印

package mainimport "fmt"func swap(x, y string) (string, string) {return y, x
}func main() {a, b := swap("hello", "world")fmt.Println(a, b)
}

image-20240326223429825

案例2:函数调用,多返回值

package mainimport "fmt"func main() {//函数的调用printinfo()myprint("haha")c := add2(2, 3)myprintnum(c)x, y := swap("yueliusu", "you do it!")fmt.Println(x, y)
}// 无参无返回值的函数
func printinfo() {fmt.Println("printinfo")
}// 有一个参数的函数
func myprint(msg string) {fmt.Println(msg)
}func myprintnum(x int) {println(x)
}/* 有两个参数的函数 */
// 有一个返回值的函数
func add2(a, b int) int {c := a + breturn c
}// 有多个返回值的函数
func swap(x, y string) (string, string) {return y, x
}

image-20240326223622407

2、函数参数与作用域

①可变参数

在Go语言中,函数的参数数量可以是可变的,称为可变参数。通过在参数类型前加上...符号来表示。

案例1:求和

package mainimport "fmt"func sum(nums ...int) {total := 0for _, num := range nums {total += num}fmt.Println(total) 
}func main() {sum(1, 2)sum(1, 2, 3)
}

image-20240326224548809

案例2:不同参数

package mainimport "fmt"func main() {getSum("hahah", 1, 2, 3, 4, 5, 6, 7)
}//在Go中,可变参数通过在参数类型前加上省略号 ... 来指定。
//这种参数在函数内部表现为同类型的切片(slice)。// 参数 ...参数类型 <------> 可变参数
func getSum(msg string, nums ...int) {fmt.Println(msg)sum := 0for i := 0; i < len(nums); i++ {fmt.Println(nums[i])sum += nums[i]}fmt.Println("sum:", sum)
}//若一个函数的参数有可变参数的同时还有其它参数,可变参数要放参数列表最后的位置
//一个函数的参数列表最多只能有一个可变参数
②形式参数与实际参数
  • 形式参数

    定义函数时,用于接收外部传入值的变量称为形式参数。(接收到)

  • 实际参数

    在调用函数时,传递给函数的实际值或变量称为实际参数。(传递给)

package mainfunc main() {// 形参与实参要一一对应,顺序,个数,类型// 实际参数println(max(1, 2))
}//形式参数:定义函数时,用于接收外部传入值的 变量 称为形式参数
//实际参数:在调用函数时,传递给函数的实际值或变量称为实际参数// max函数,实现两个数值比较大小
// 形式参数
func max(num1, num2 int) int {var result intif num1 > num2 {result = num1} else {result = num2}//函数定义时有说明返回值的类型,那么函数中必须使用return语句来返回值return result
}

image-20240326224206897

③参数的传递细节

Go语言中函数的参数是通过值传递的,这意味着函数接受的是参数值的一个副本。但是,如果参数是指针、切片或映射等引用类型,则函数可以修改原始数据。

  • 引用传递 ( 切片 )

    引用传递 操作的是数据的地址 如:slice、map、chan…

  • 值传递 ( 数组 )

    值传递 操作的是数据本身 如:基础数据类型int、string、bool、floa64、array、struct…

案例1:引用传递,数据修改

package mainimport "fmt"func modify(s []int) {s[0] = 100
}func main() {a := []int{1, 2, 3}modify(a)fmt.Println(a) // 输出 [100, 2, 3],原始数据被修改
}

image-20240326224746713

案例2:值传递,接收与修改数据

package mainimport "fmt"func main() {//值传递arr := [4]int{1, 2, 3, 4}fmt.Println(arr)//值传递:拷贝实际参数arr的值给形式参数arr2update(arr)fmt.Println("调用函数后数据被修改为:", arr)//调用函数后,arr中的数据并未发生变化,说明是值传递//修改arr2的值并不会影响到arr的值//值传递:传递的是数据的副本,此时修改副本的数据,对原数据并不影响,究其根本在于二者并不在同一内存空间//引用传递//见下个案例
}//值传递 操作的是数据本身 如:基础数据类型int、string、bool、floa64、array、struct...
//引用传递 操作的是数据的地址 如:slice、map、chan...func update(arr2 [4]int) {fmt.Println("arr2接收的数据:", arr2)arr2[0] = 100fmt.Println("arr2修改后的数据:", arr2)
}

image-20240326224920045

案例3:引用传递,切片

package mainimport "fmt"func main() {//定义一个切片s1 := []int{1, 2, 3, 4}fmt.Println("s1默认数据", s1)update2(s1)fmt.Println("调用函数后s1的数据为:", s1)}//引用传递,传递的是数据的地址,当修改该数据时,由于和原数据共处同一地址处,原数据也会随着修改func update2(s2 []int) {fmt.Println("s2 接收到的数据为:", s2)s2[0] = 10fmt.Println("s2[0]被修改后,s2的数据为:", s2)
}

image-20240326225156187

④函数作用域

变量的作用域是程序中变量可以正常访问的范围。在Go中:

  • 局部变量

    函数内定义的变量,它只在函数体内部或语句块内部可见。

  • 全局变量

    函数外部定义的变量。

案例1:内部与外部

package mainimport "fmt"func main() {x := "outside"{y := "inside"fmt.Println(y) // 输出 inside}fmt.Println(x) // 输出 outside// fmt.Println(y) // 编译错误:y在这里不可见
}

image-20240326225358932

案例2:局部变量,就近原则

package mainimport "fmt"var num int = 50// 全局变量是 在函数外部定义的 变量
// 局部变量是 在函数内或语句块内定义的 变量 。它们只能在其定义的函数或语句块内部被访问。
func main() {//函数体内的局部变量temp := 100if b := 1; b <= 10 {//语句体内的局部变量temp := 50fmt.Println(temp) //局部变量 遵循就近原则fmt.Println(b)}fmt.Println(temp)fmt.Println(num)f1()f2()
}func f1() {num := 40fmt.Println(num)
}func f2() {fmt.Println(num)
}
⑤递归函数

递归函数是指一个函数在其定义中调用自己的函数。递归允许程序以简洁的方式解决复杂问题,在数据量小的时候,使用递过来实现是十分简便的,但是若数据量较大,不建议再使用递归函数来解决,因为这会占用太大的空间,程序效率较低。

因此,总结一下,使用递归时,一般需要注意以下几点:

  1. 确保有终止条件:递归函数必须有一个明确的终止条件,否则会无限递归下去,导致栈溢出错误。终止条件通常是一个或多个基案(base case),即最简单的问题实例,可以直接解答,不需要进一步递归。
  2. 注意栈空间的使用:每次函数调用时,都会在栈上为其分配空间来保存参数、局部变量和返回地址等信息。递归调用过深可能会耗尽栈空间,导致栈溢出。因此,对于可能导致深层递归的问题,需要谨慎设计递归逻辑,或考虑使用迭代等其他方法。
  3. 递归深度限制:在某些情况下,特别是处理大数据量或深度嵌套的数据结构时,考虑设置递归深度限制,以避免可能的栈溢出或过度消耗资源。

案例1:递归求阶乘

package mainimport "fmt"func factorial(n int) int {if n == 0 {return 1}return n * factorial(n-1)
}func main() {fmt.Println(factorial(5)) // 输出 120
}

image-20240326230402126

案例2:递归求和

image-20230209215533739

package mainimport "fmt"func main() {sum := Sum(5)fmt.Println(sum)
}// 递归函数 函数自己调用自己
// 递归需要有出口,也就是边界条件,否则会无限调用下去,导致栈溢出,系统崩溃
func Sum(n int) int {if n == 1 {return 1}return Sum(n-1) + n
}

image-20240326230529889

3、小结

  • 什么是函数?函数定义
  • 多个返回值的函数
  • 多个参数、可变参数 …
  • 参数的作用域( 小范围的可以用大范围的变量,反之则不行 )
  • 递归函数(函数自己调用自己,可能会导致栈溢出 … ,需要有终止条件或限制)

很感谢你能看到这里,如有相关疑问,还请下方评论留言。
Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊)
希望本篇内容能对大家有所帮助,如果大家喜欢的话,请动动手点个赞和关注吧,非常感谢你们的支持!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Visio Viewer for Mac(Visio文件查看工具)

Visio Viewer for Mac是一款专为Mac用户设计的Microsoft Visio文件查看器。它拥有直观易用的用户界面&#xff0c;使得用户可以快速加载和显示Visio文件&#xff0c;无需安装完整的Microsoft Visio软件。 软件下载&#xff1a;Visio Viewer for Mac3.1.0激活版 Visio Viewer fo…

配置Web运行环境与第一个网页

安装与配置Web环境: 如下使用了VSC作为web的运行环境。 下面是VSC的官网点击进入:Download Visual Studio Code - Mac, Linux, Windowshttps://code.visualstudio.com/download 1.下载 进入官网后可以看到有windows&#xff0c;linux&#xff0c;还有苹果按照自己的系统下载&…

204基于matlab的图像融合

基于matlab的图像融合&#xff0c;包括三种方式&#xff0c;加权、PCA、IHS变换。比较三者融合后的图像差异。程序已调通&#xff0c;可直接运行。 204 matlab 图像融合 信息融合 - 小红书 (xiaohongshu.com)

Chrome/Edge 使用 Markdown Viewer 查看 Markdown 格式文件

Chrome/Edge 使用 Markdown Viewer 查看 Markdown 格式文件 0. 引言1. 安装 Markdown Viewer 插件2. 使用 Markdown Viewer 阅读 Markdown 格式文件 0. 引言 大部分程序员都喜欢 Markdown 格式的文件&#xff0c;这时给一些没有在电脑上安装 Markdown 编辑器的同事分享资料时&…

负氧离子监测站:创造健康生活环境

TH-FZ5在蓝天白云之下&#xff0c;那一座座高耸的全彩屏负氧离子监测站&#xff0c;如同一支支科技的绿芽&#xff0c;静静破土而出&#xff0c;为这片土地带来了新的生命力。这些现代化的设备不仅美化了环境&#xff0c;更是我们呼吸健康守护者&#xff0c;它们的存在让我们的…

使用ai智能写作场景之gpt整理资料,如何ai智能写作整理资料

Ai智能写作助手&#xff1a;Ai智能整理资料小助手 Ai智能整理资料小助手可试用3天&#xff01; 通俗的解释一下怎么用ChatGPT来进行资料整理&#xff1a; 搜寻并获取指定数量的特定领域文章&#xff1a; 想像你在和我说话一样&#xff0c;告诉我你想要多少篇关于某个话题的文…

oracle补丁升级(19.3-19.22)

一、备份原来的opatch和数据库文件 这里要根据自己的路径&#xff1a; mv /u01/app/oracle/product/19.3.0/db_1/OPatch /u01/app/oracle/product/19.3.0/db_1/OPatch.bakcd /u01/app mkdir -p /u01/app/backup tar -pcvf /u01/app/backup/oracle_backup.tar /u01/app/oracle/…

俚语加密漫谈

俚语加密是一种古老而有效的通信方式&#xff0c;将特定词语或短语在群体内赋予特殊含义&#xff0c;从而隐藏真实信息。类似于方言&#xff0c;它在历史上的应用不可忽视。随着计算机时代的到来&#xff0c;现代密码学通过数学运算编织密语&#xff0c;使得加密变得更加高深莫…

C语言运算符优先级介绍

1. 引言 什么是运算符 运算符是编程中用于执行算术、比较和逻辑操作的符号。它们是构建表达式的基本工具&#xff0c;类似于数学中的加、减、乘和除。 程序片段示例: 简单的算术运算符使用 #include <stdio.h>int main() {int a 5, b 2;int sum a b; // 使用加法…

数据结构(五)单链表专题

在开始之前&#xff0c;我先来给大家讲一下顺序表与链表的区别&#xff1a; 它们在堆上存储的差异&#xff1a; 我们可以很容易的知道&#xff0c;循序表是连续的有序的&#xff0c;但链表是杂乱的&#xff0c;它们通过地址彼此联系起来。 1. 链表的概念及结构 概念&#xff1…

高效解决Visual Studio无法识别到自定义头文件

文章目录 问题解决方案 问题 说明你没有好好配置项目属性 解决方案 把头文件都集中存放到一个文件夹里 之后我会持续更新&#xff0c;如果喜欢我的文章&#xff0c;请记得一键三连哦&#xff0c;点赞关注收藏&#xff0c;你的每一个赞每一份关注每一次收藏都将是我前进路…

掌握ES6的箭头函数:深入了解其实用性与规则

引言 ES6&#xff08;ECMAScript 2015&#xff09;引入了箭头函数&#xff0c;这是一种新的函数声明方式&#xff0c;它改变了我们编写JavaScript代码的方式。箭头函数提供了更简洁、更直观的语法&#xff0c;并且具有一些独特的特性和行为。本文将深入探讨箭头函数的规则、用…