当前位置: 首页 > news >正文

7、函数与异常

目录

  • 一、函数的概念
  • 二、匿名函数
  • 三、闭包
  • 四、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")
}

相关文章:

7、函数与异常

目录一、函数的概念二、匿名函数三、闭包四、defer五、异常机制一、函数的概念 函数的基本形式 //函数定义。a,b是形参 func argf(a int, b int) { a a b } var x, y int 3, 6 argf(x, y) //函数调用。x,y是实参函数参数&#xff1a; func arg2(a, b int) { //参数类型相…...

Julia 语言环境安装

Julia 语言支持以下系统&#xff1a; LinuxFreeBSDmacOSWindowsAndroid Julia 安装包下载地址为&#xff1a;Download Julia。 Github 源码地址&#xff1a;GitHub - JuliaLang/julia: The Julia Programming Language。 国内镜像地址&#xff1a;Index of /julia-releases/…...

5.1 线程

文章目录1.概述2.多线程的特性2.1 随机性2.2 CPU分时调度2.3 线程的状态2.4 线程状态与代码对照3.多线程代码实现方式1:继承Thread3.1 概述3.2 常用方法3.3 测试多线程的创建方式14.多线程代码实现方式2:实现Runnable接口4.1 概述4.2 常用方法4.3 练习2&#xff1a;测试多线程的…...

通讯录的实现

一、目的&#xff1a;使用C实现通讯录二、包含功能&#xff1a;添加联系人:向通讯录中添加新人&#xff0c;信息包括&#xff08;姓名、性别、年龄、联系电话、家庭住址&#xff09;最多记录1000人显示联系人:显示通讯录中所有联系人信息删除联系人:按照姓名进行删除指定联系人…...

Urho3D导航

Urho3D通过使用Recast和Detour库实现导航网格生成和路径查找。 导航功能通过NavigationMesh和Navigable组件公开。 NavigationMesh从已使用Navigable组件标记的子节点收集几何体。默认情况下&#xff0c;可导航组件的行为是递归的&#xff1a;除非禁用递归&#xff0c;否则也…...

【学习总结】激光雷达与相机外参标定:代码(cam_lidar_calibration)

前段时间尝试了一款激光雷达和相机标定的代码&#xff0c;总结了博客&#xff1a; 【学习总结】激光雷达与相机外参标定&#xff1a;原理与代码 但总觉得那个代码太差劲&#xff0c;而且精度不行&#xff0c;于是又找了些新的代码&#xff0c;体验比之前的好很多&#xff0c;在…...

车载技术开发—{Android CarFrameWork}

Android Automotive平台 Android Automotive是通过Android的通用框架&#xff0c;语言和API来实现的一个全栈&#xff0c;开源&#xff0c;高度可定制的平台。 Android Automotive与整个Android生态系统的关系 Android Automotive是Android的一部分。 Android Automotive不是…...

多城市二手车买卖发布管理小程序开发

多城市二手车买卖发布管理小程序开发 功能特性: 为你介绍二手车微信小程序的功能特性。 车辆分类搜索&#xff0c;支持按品牌、售价、年龄、上牌时间、排量等筛选。 车源发布&#xff0c;支持用户一键发布二手车&#xff0c;平台审核上线&#xff0c;发布可编辑、删除等操作。…...

企业级信息系统开发学习笔记1.2 初探Spring——利用组件注解符精简Spring配置文件

文章目录零、本讲学习目标一、课程引入二、打开项目 - SpringDemo三、利用组件注解符精简Spring配置文件&#xff08;一&#xff09;创建新包&#xff08;二&#xff09;复制四个类&#xff08;三&#xff09;修改杀龙任务类&#xff08;四&#xff09;修改救美任务类&#xff…...

37、基于51单片机乒乓球比赛系统设计

摘要 乒乓球游戏电路是一个对输入信号、输入时机正确与否的8个LED表示乒乓球球台和乒乓球&#xff0c;用数码管模拟显示器&#xff0c;显示比赛局数比分和每局玩家得分的电路。电路并不复杂&#xff0c;整体分为两个模块&#xff1a;一&#xff0c;游戏主模块&#xff1b;二&a…...

VMware虚拟机安装Win11最详细过程以及遇到的这台电脑无法运行Windows11的问题

准备工作 在使用VMware虚拟机安装Win11之前我们先把准备工作做好&#xff0c;以免后续思绪混乱导致出错。 1. 到VMware官网或点击链接下载正版VMware Workstation 16 Pro。 2. 双击打开安装包&#xff0c;点击下一步。 3. 阅读用户许可协议&#xff0c;勾选我接受许可协议中的…...

centos误删python2后怎么重新安装

此教程为离线安装 一. 先查询系统版本 cat /proc/version Linux version 3.10.0-1127.el7.x86_64 (mockbuildkbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) ) #1 SMP Tue Mar 31 23:36:51 UTC 2020 二. 安装python2.7.5(已知原python版…...

Qt 开发使用VSCode 笔记2

在之前有写过使用VSCode开发QT的笔记 Qt 开发使用VSCode 在以前的基础上继续学习记录写下《Qt 开发使用VSCode 笔记2》 该笔记相比之前的Qt 开发使用VSCode新加了如下内容&#xff1a; 工作区的使用使用Natvis进行Qt感知对象可视化通过vscode创建QT Quick项目 工作区的使用 …...

查找算法复习

先序在了解查找算法之前&#xff0c;需要熟悉几个概念&#xff0c;不然后面容易产生理解错误。查找表&#xff1a;即被查找的对象&#xff0c;通常由几个关键字组成。关键字&#xff1a;就是数据项、字段的意思。关键字有主次之分&#xff0c;其中主关键字取值是唯一的。查找长…...

腾讯前端必会面试题(必备)

如何提取高度嵌套的对象里的指定属性&#xff1f; 有时会遇到一些嵌套程度非常深的对象&#xff1a; const school {classes: {stu: {name: Bob,age: 24,}} }像此处的 name 这个变量&#xff0c;嵌套了四层&#xff0c;此时如果仍然尝试老方法来提取它&#xff1a; const {…...

探访上汽通用武汉奥特能超级工厂

上汽通用汽车在电动化和智能网联化新技术领域投入了700亿大洋&#xff0c;武汉奥特能超级工厂就是其中一个重点项目。这个工厂已经投产&#xff0c;将成为上汽通用汽车的新能源生产基地&#xff0c;加速奥特能平台车型的推出。 最近别克推出了Electra E5&#xff0c;它是别克第…...

【Linux】线程函数和线程同步详细整理(金针菇般细)

目录 一&#xff0c;线程函数 1.获取当前线程ID 2.创建线程 3.退出线程 4.阻塞线程 5.分离线程 6.取消线程 7.线程比较 8.测试代码&#xff08;线程函数总结&#xff09; 二&#xff0c;线程同步 1.互斥锁 2.读写锁 3.条件变量 4.信号量 一&#xff0c;线程函数 …...

Python学习笔记6:抽象

抽象 函数 判断某个对象是否可调用&#xff0c;可使用内置函数callable >>> import math >>> x 1 >>> y math.sqrt >>> callable(x) False >>> callable(y) True斐波那契数组 def fibs(num): result [0, 1] for i i…...

自己手写一个redux

提起 Redux 我们想到最多的应该就是 React-redux 这个库&#xff0c;可是实际上 Redux 和 React-redux 并不是同一个东西, Redux 是一种架构模式&#xff0c;源于 Flux。 React-redux 是 Redux 思想与 React 结合的一种具体实现。 在我们使用 React 的时候&#xff0c;常常会遇…...

mysql调优参数

my.conf [client] port 端口 socket sokcet位置 [mysqld] basedir mysql位置 port 3306 socket sokcet位置 datadir data目录 pid_file mysqld.pid位置 bind_address 0.0.0.0 lower_case…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...