7、函数与异常

news/2024/4/26 12:34:53/文章来源:https://blog.csdn.net/qq23001186/article/details/129103019

目录

  • 一、函数的概念
  • 二、匿名函数
  • 三、闭包
  • 四、defer
  • 五、异常机制

一、函数的概念

  • 函数的基本形式
//函数定义。a,b是形参
func argf(a int, b int) { a = a + b 
}
var x, y int = 3, 6
argf(x, y) //函数调用。x,y是实参
  • 函数参数
func arg2(a, b int) { //参数类型相同时可以只写一次a = a + b//不写return时,默认执行完最后一行代码函数返回
}func arg3(a, b *int) { //如果想通过函数修改实参,就需要指针类型*a = *a + *b*b = 888
}func no_arg() { //函数可以没有参数,也没有返回值fmt.Println("欢迎开启Golang之旅")
}func return1(a, b int) int { //函数需要返回一个int型数据a = a + bc := a //声明并初始化一个变量creturn c
}func return2(a, b int) (c int) { //返回变量c已经声明好了a = a + bc = a  //直接使用creturn //由于函数要求有返回值,即使给c赋过值了,也需要显式写return
}func return3() (int, int) { //可以没有形参,可以返回多个参数now := time.Now()return now.Hour(), now.Minute()
}
  • slice、map、channel作为函数参数
    • slice、map、channel都是引用类型
    • 它们作为函数参数时其实跟普通struct没什么区别
    • 都是对struct内部的各个字段做一次拷贝传到函数内部
func slice_arg_1(arr []int) { //slice作为参数,实际上是把slice的arrayPointer、len、cap拷贝了一份传进来arr[0] = 1           //修改底层数据里的首元素arr = append(arr, 1) //arr的len和cap发生了变化,不会影响实参
}func main() {arr := []int{8}slice_arg_1(arr)fmt.Println(arr[0])   //1fmt.Println(len(arr)) //1
}
  • 不定长参数:不定长参数实际上是slice类型
//不定长参数
func variable_ength_arg(a int, other ...int) int { //调用该函数时,other可以对应0个参数也可以对应多个参数sum := a//不定长参数实际上是slice类型for _, ele := range other {sum += ele}if len(other) > 0 {fmt.Printf("first ele %d len %d cap %d\n", other[0], len(other), cap(other))} else {fmt.Printf("len %d cap %d\n", len(other), cap(other))}return sum
}func main() {variable_ength_arg(1, 2, 3, 4, 5) //first ele 2 len 4 cap 4
}
  • append函数接收的就是不定长参数func append(slice []Type, elems ...Type) []Type
func main() {arr := []int{4, 5, 6}//append函数接收的就是不定长参数arr = append(arr, 1, 2, 3)arr = append(arr, 7)fmt.Printf("new arr %v\n", arr) //new arr [4 5 6 1 2 3 7]
}
  • **递归函数 **:函数自己调用自己
// 斐波那契数列前10个数为:0,1,1,2,3,5,8,13,21,34
func Fibonacci(n int) int {if n == 0 || n == 1 {return n //凡是递归,一定要有终止条件,否则会进入无限循环}return Fibonacci(n-1) + Fibonacci(n-2) //递归调用函数自身
}

二、匿名函数

  • 函数也是一种数据类型
func function_arg1(f func(a, b int) int, b int) int { //f参数是一种函数类型a := 2 * breturn f(a, b)
}type foo func(a, b int) int //foo是一种函数类型
func function_arg2(f foo, b int) int { //参数类型看上去简洁多了a := 2 * breturn f(a, b)
}type User struct {Name  stringbye   foo                      //bye的类型是foo,而foo代表一种函数类型hello func(name string) string //使用匿名函数来声明struct字段的类型
}func main() {ch := make(chan func(string) string, 10)ch <- func(name string) string { //使用匿名函数return "hello " + name}
}
  • 实例1
var sum = func(a, b int) int {return a + b
}type add func(a, b int) intfunc op(f add, a int) int {b := 2 * areturn f(a, b)
}func main() {fmt.Println(sum(1, 2))  //3fmt.Println(op(sum, 2)) //6
}
  • 实例2
type User struct {Name stringRec  func(int, int) int
}func add(a, b int) int {return a + b
}func sub(a, b int) int {return a - b
}func main() {user := User{Name: "hello", Rec: add}fmt.Println(user.Rec(1, 2)) // 3user.Rec = subfmt.Println(user.Rec(1, 2)) // -1}

三、闭包

  • 闭包概念
    • 闭包(Closure)是引用了自由变量的函数
    • 自由变量将和函数一同存在,即使已经离开了创造它的环境
    • 闭包复制的是原对象的指针
func sub() func() {i := 10fmt.Printf("%p\n", &i)b := func() {fmt.Printf("i addr %p i = ", &i)i--fmt.Println(i)}return b
}func main() {//对于sub来讲,i是局部变量,正常情况下离开了sub就被释放了//但是因为闭包函数b的存在,接下来的2个f()调用仍然是对原局部变量i的地址进行操作f := sub() //0xc000122058f()        //i addr 0xc0000180a8 i = 9f()        //i addr 0xc0000180a8 i = 8}
  • 闭包案例
    • tmp1与传入base=10一同存在
    • tmp2(这里base被初始化为10)与传入base=10一同存在
    • 可以看到tmp1和tmp2的函数地址是不一样的
func add(base int) func(int) int {return func(i int) int {fmt.Printf("base addr %p\n", &base)base += ireturn base}
}func main() {tmp1 := add(10)fmt.Println(tmp1(1), tmp1(2))// base addr 0xc0000a6058// base addr 0xc0000a6058// 11 13tmp2 := add(10)fmt.Println(tmp2(1), tmp2(2))// base addr 0xc0000a6090// base addr 0xc0000a6090// 11 13
}

四、defer

  • defer概念

    • defer用于注册一个延迟调用(在函数返回之前调用)
    • defer典型的应用场景是释放资源,比如关闭文件句柄,释放数据库连接等
  • 如果同一个函数有多个defer,则后注册的先执行

func basic() {fmt.Println("A")defer fmt.Println("B")//如果同一个函数有多个defer,则后注册的先执行defer fmt.Println("C")fmt.Println("D")
}func main() {basic() // A D C B
}
  • defer后接func和接表达式
    • defer后接func的时候,不会拷贝变量
    • defer后面不是跟func,而直接跟一条执行语句,则相关变量在注册defer时被拷贝或计算
func defer_exe_time() (i int) {i = 9defer func() {fmt.Printf("defer_B i=%d\n", i) //打印5而非9}()defer func(i int) {fmt.Printf("defer_C i=%d\n", i)}(i) //i=9,在注册的时候这里i已经拷贝了9defer fmt.Printf("defer_A i=%d\n", i) //变量在注册defer时被拷贝或计算return 5
}func main() {defer_exe_time()// defer_A i=9// defer_C i=9// defer_B i=5
}
  • defer-panic:func内部如果发生panic,会把panic暂时搁置,当把其他defer执行完之后再来执行这个panic
func defer_panic() {defer fmt.Println("11111111")n := 0defer func() {fmt.Println(2 / n)defer fmt.Println("2222222")}()defer fmt.Println("33333333")
}func main() {defer_panic()
}//33333333
//11111111
//发生异常: panic
//"runtime error: integer divide by zero"
//Stack:
//	3  0x0000000000448726 in main.defer_panic.func1
//	    at c:/develop_project/go_project/proj1/main.go:9
//	5  0x0000000000448465 in main.defer_panic
//	    at c:/develop_project/go_project/proj1/main.go:13
//	6  0x00000000004488d7 in main.main
//	    at c:/develop_project/go_project/proj1/main.go:16

五、异常机制

  • error:go语言没有try catch,它提倡返回error
func divide(a, b int) (int, error) {if b == 0 {return -1, errors.New("divide by zero")}return a / b, nil
}func main() {if res, err := divide(3, 0); err != nil {fmt.Println(err.Error()) //divide by zero} else {fmt.Println(res)}
}
  • 自定义error
type PathError struct {path       stringop         stringcreateTime stringmessage    string
}func NewPathError(path, op, message string) PathError {return PathError{path:       path,op:         op,createTime: time.Now().Format("2006-01-02"), //yyyy-MM-ddmessage:    message,}
}func (e PathError) Error() string {return e.createTime + ":" + e.op + " " + e.path + " " + e.message
}func deletePath(path string) error {return NewPathError(path, "delete", "path not exits")
}
  • 何时会发生panic
    • 运行时错误会导致panic,比如数组越界、除0
    • 程序主动调用panic(error)
  • panic会执行什么
    • 逆序执行当前goroutine的defer链(recover从这里介入)
    • 打印错误信息和调用堆栈
    • 调用exit(2)结束整个进程
  • recover:recover会阻断panic的执行
func soo() {defer func() {if err := recover(); err != nil {fmt.Println("发生了panic,不让程序退出")}}()panic(errors.New("这是错误信息"))
}func main() {soo()fmt.Println("333333333")
}

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

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

相关文章

Python采集双色球数据,做数据分析,让我自己实现自己的富豪梦

来唠点嗑&#xff1f; 咳咳&#xff0c;最近是咋的了&#xff0c;某站掀起了一股双色球热潮&#xff1f;一般我自己的账号上&#xff0c;是很少看到关于python这些内容的&#xff0c;都是小姐姐和热梗&#xff0c;或者其他搞笑视频 由于&#x1f4b4;的吸引力…手不自觉的就点…

2023年TS4 入门笔记【慕课网imooc】【Vue3+React18 + TS4考勤系统】

目录 安装ts 基础 类型声明和变量声明 类型注解和类型判断 类型分类与联合类型与交叉类型​编辑 never类型与any类型与unknown类型 类型断言与非空断言 数组类型和元祖类型 对象类型与索引签名 函数类型与void类型 函数重载与可调用注解 枚举类型与const枚举 进阶…

2023年美国大学生数学建模A题:受干旱影响的植物群落建模详解+模型代码(二)

前言 资源放CSDN上面过不了审核,都快结束了都没过审真的麻了,订阅专栏的同学直接加我微信直接发你。我只打造优质专栏。专注建模四年,博主参与过大大小小数十来次数学建模,理解各类模型原理以及每种模型的建模流程和各类题目分析方法。此专栏的目的就是为了让零基础快速使…

【2023-02-20】JS逆向之翼支付

提示&#xff1a;文章仅供参考&#xff0c;禁止用于非法途径 文章目录前言分析总结前言 真的好久没更了…… 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 分析 进到网页&#xff0c;加载两个接口 applyLoginFactor 接口返回一个RSA公钥&#xff0…

工业4.0和工业物联网如何协同工作

虽然许多公司已经接受了工业物联网&#xff0c;但他们现在必须接受工业4.0对数据驱动的数字化转型的承诺。随着制造业、能源、公用事业和供应链应用迅速采用工业物联网(IIoT)&#xff0c;这些行业的新现实正在形成。工业物联网提供了企业管理数千个活动部件所需的数据类型&…

【部署】项目正式服部署更新

chihiro-notes 千寻简笔记 v0.1 内测版 &#x1f4d4; 笔记介绍 大家好&#xff0c;千寻简笔记是一套全部开源的企业开发问题记录&#xff0c;毫无保留给个人及企业免费使用&#xff0c;我是作者星辰&#xff0c;笔记内容整理并发布&#xff0c;内容有误请指出&#xff0c;笔…

第一章 初识 Spring Security

第一章 初识 Spring Security 1、权限管理 权限管理 基本上涉及到用户参与的系统都要进行权限管理&#xff0c;权限管理属于系统安全的范畴&#xff0c;权限管理实现了对用户访问系统的控制&#xff0c;按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资…

计算机网络学习笔记02

学习视频&#xff1a;https://www.bilibili.com/video/BV1c4411d7jb/?p7&spm_id_frompageDriver&vd_source75dce036dc8244310435eaf03de4e330 一、计算机网络体系结构 1 常见的计算机网络体系结构 OSI体系结构和TCP/IP体系结构 TCP/IP体系结构的网络接口层并没有规…

鼠标指针文件格式解析

鼠标指针文件格式解析 文章目录鼠标指针文件格式解析windowsico文件格式分析文件头&#xff1a;图像数据头段&#xff1a;图像数据段&#xff1a;Ani动态光标格式解析数据结构&#xff1a;anihseq **rate**LISTcur静态光标文件格式解析macOSLinuxwindows ico文件格式分析 是一…

【Java基础】IO流

IO流 最后一定要关闭流&#xff0c;防止资源泄露 字节流 一次读取1字节&#xff0c;8比特 FileInputStream import org.junit.jupiter.api.Test;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException;public class CopyBytes {pub…

分布式之Raft共识算法分析

写在前面 在分布式之Paxos共识算法分析 一文中我们分析了paxos算法&#xff0c;知道了其包括basic paxos和multi paxos&#xff0c;并了解了multi paxos只是一种分布式共识算法的思想&#xff0c;而非具体算法&#xff0c;但可根据其设计具体的算法&#xff0c;本文就一起来看…

DAMA认证|数据治理产业上规模需要做到“三化”

数据治理是开启数据安全体系化建设的第一步&#xff0c;需要从产业层面做大做强&#xff0c;支撑数据安全整体框架&#xff0c;为数据流通提供安全保障&#xff0c;推动促进数字化产业进一步发展。 规模化发展是数据治理产业的瓶颈&#xff0c;行业数字化业务的复杂性和过多的定…

Spring Boot 日志文件,你都会了吗?

目录 1、日志文件的作用 2、日志的使用 2.1、从程序中得到日志对象 2.2、使用日志 2.3、日志格式 3、日志级别 3.1、这样的日志级别有什么用&#xff1f; 3.2、日志级别分类和使用 3.3、日志级别设置 4、日志持久化 5、更简单的日志输出——lombok 5.1、对比 5.2、…

Linux下安装MySQL8.0的详细步骤(解压tar.xz安装包方式安装)

Linux下安装MySQL8.0的详细步骤 第一步&#xff1a;下载安装配置 第二步&#xff1a;修改密码&#xff0c;并设置远程连接&#xff08;为了可以在别的机器下面连接该mysql&#xff09; 第三步&#xff1a;使用Navicat客户端连接 搞了一台云服务器&#xff0c;首先要干的活就是…

批处理删除指定文件或文件夹

声明&#xff1a;1-2节参考了 https://blog.csdn.net/weixin_43960383/article/details/1243673841. DEL1.1 DEL 的命令参数使用 del 命令能指定文件&#xff0c;Del (erase)[Drive:][Path]FileName指删除指定文件。指定要删除的文件或文件集的位置和名称。语法格式如下&#x…

Unity毛发系统TressFX Exporter

Unity 数字人交流群&#xff1a;296041238 一&#xff1a;在Maya下的TressFX Exporter 插件安装步骤&#xff1a; 1. 下载Maya的TressFX Exporter插件 下载地址&#xff1a;TressFX Exporter 链接&#xff1a;https://github.com/Unity-China/cn.unity.hairfx.core/tree/m…

利用OpenCV的函数equalizeHist()对图像作直方图均衡化处理

如果一幅图像的灰度值集中在某个比较窄的区域&#xff0c;则图像的对比度会显得比较小&#xff0c;不便于对图像的分析和处理。 图像的直方图均衡化可以实现将原图像的灰度值范围扩大&#xff0c;这样图像的对比度就得到了提高&#xff0c;从而方便对图像进行后续的分析和处理…

Cosmos 基础教程(二)-- Run a Node, API, and CLI

有很多不同的方法来运行Cosmos区块链的节点。您将探索如何使用simapp 进行此操作。 1、编译simapp Cosmos SDK存储库包含一个名为 simapp 的文件夹。在这个文件夹中&#xff0c;您可以找到运行Cosmos SDK模拟版本的代码&#xff0c;这样您就可以在不实际与链交互的情况下测试…

化解射频和微波设计挑战的六个技巧

即使是最自信的设计人员&#xff0c;对于射频电路也往往望而却步&#xff0c;因为它会带来巨大的设计挑战&#xff0c;并且需要专业的设计和分析工具。这里将为您介绍六条技巧&#xff0c;来帮助您简化任何射频PCB 设计任务和减轻工作压力&#xff01; 1、保持完好、精确的射频…

由浅入深,一起来刷Java高级开发岗面试指南,面试必定无忧!

前言 我只想面个CV工程师&#xff0c;面试官偏偏让我挑战造火箭工程师&#xff0c;加上今年这个情况更是前后两男&#xff0c;但再难苟且的生活还要继续&#xff0c;饭碗还是要继续找的。在最近的面试中我一直在总结&#xff0c;每次面试回来也都会复盘&#xff0c;下面是我根…