【Golang】深入解读Go语言中的错误(error)与异常(panic)

✨✨ 欢迎大家来到景天科技苑✨✨
🎈🎈 养成好习惯,先赞后看哦~🎈🎈
🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,Golang开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。所属的专栏:Go语言开发零基础到高阶实战
景天的主页:景天科技苑

文章目录
- Go语言中的错误与异常
- 1. Go语言错误 error
- (1)自定义错误
- 1. 使用errors.New()
- 2.使用fmt.Errorf()
- 3. 综合案例
- (2)自定义错误类型(难点)
- 1、定义一个结构体
- 2、为该结构体创建个方法,实现go内置error接口中的Error方法
- 3、创建个方法测试
- 4、main方法中写逻辑
- 2. Go语言的异常处理机制
- (1)使用panic
- (2)使用recover
- 1. recover案例展示
- 2. recover结合多个defer执行顺序
Go语言中的错误与异常
在Go语言编程中,错误和异常处理是非常重要的一部分。Go语言通过其独特的错误处理机制和异常处理模型,提供了一种既清晰又高效的方式来处理程序运行时的错误和异常情况。
错误:指的是程序中预期会发生的结果,预料之中
打开一个文件:文件正在被占用,可知的。
异常:不该出现问题的地方出现了问题,预料之外
调用一个对象,发现这个对象是个空指针对象,发生错误。
错误是业务的一部分,而异常不是。
go语言开发过程中遇到最多的代码,就是error。
需要将所有的错误情况都考虑到,并写到你的代码中。
1. Go语言错误 error
鼓励工程师在代码中显式的检查错误,而非忽略错误。
错误是开发中必须要思考的问题
- 某些系统错误 ,文件被占用,网络有延迟
- 人为错误:核心就是一些不正常的用户会怎么来给你传递参数,sql注入
在实际工程项目中,
我们希望通过程序的错误信息快速定位问题,但是又不喜欢错误处理代码写的冗余而又啰嗦。
Go语言没有提供像Java. c#语言中的try…catch异常处理方式,
而是通过函数返回值逐层往上抛, 如果没有人处理这个错误,程序就终止 panic
这种设计,鼓励工程师在代码中显式的检查错误,而非忽略错误。
好处就是避免漏掉本应处理的错误。但是带来一个弊端,让代码繁琐。
Go中的错误也是一种类型。错误用内置的error类型表示。就像其他类型的,如int, float64。
错误值可以存储在变量中,从函数中返回,传递参数 等等。
代码示例:
package mainimport ("fmt""os"
)// 错误是开发中必须要思考的问题
// - 某些系统错误 ,文件被占用,网络有延迟
// - 人为错误:核心就是一些不正常的用户会怎么来给你传递参数,sql注入
func main() {//工作目录是指在执行程序时,操作系统认为当前正在工作的目录。//一般情况下,我们通过在终端或文件浏览器中打开文件时所处的目录就是当前工作目录。//os.Getwd()只能获取当前项目的工作目录,并不是当前文件所在路径path, _ := os.Getwd()fmt.Println("Path:", path)err := os.Chdir("F:\\goworks\\src\\jingtian\\yufa\\错误与异常")if err != nil {return}//再次查看路径path2, _ := os.Getwd()fmt.Println("再次查看Path:", path2)//打开一个文件 os 系统包,所有可以用鼠标和键盘能执行的事件,都可以用程序实现//os.Open()返回 一个文件对象和错误error// func Open(name string) (*File, error)file, err2 := os.Open("aaa.txt")// 在开发中,我们需要思考这个错误的类型 PathError// 1、文件不存在 err// 2、文件被占用 err// 3、文件被损耗 err// 调用方法后,出现错误,需要解决if err2 != nil {fmt.Println(err2)return}fmt.Println(file.Name())
}// 在实际工程项目中,
// 我们希望通过程序的错误信息快速定位问题,但是又不喜欢错误处理代码写的冗余而又啰嗦。
// Go语言没有提供像Java. c#语言中的try...catch异常处理方式,
// 而是通过函数返回值逐层往上抛, 如果没有人处理这个错误,程序就终止 panic// 这种设计,鼓励工程师在代码中显式的检查错误,而非忽略错误。
// 好处就是避免漏掉本应处理的错误。但是带来一个弊端,让代码繁琐。// Go中的错误也是一种类型。错误用内置的error类型表示。就像其他类型的,如int, float64。
// 错误值可以存储在变量中,从函数中返回,传递参数 等等。
如果文件不存在,运行就会捕获错误

文件存在,就可以正常打印文件名称

(1)自定义错误
1. 使用errors.New()
errors.New()函数是最简单的创建错误的方式。它接受一个字符串作为参数,并返回一个实现了error接口的错误值。
返回值的类型为 *errors.errorString,可以使用Error()方法,将err转化为字符串
看下源码

package mainimport ("errors""fmt"
)func main() {err := errors.New("这是一个错误")if err != nil {fmt.Println(err)fmt.Printf("错误类型%T\n", err)//可以使用Error()方法,将err转化为字符串// 注意,如果err为空,调用Error()方法会报错,所以该方法一定要在if err != nil条件中执行fmt.Printf("错误类型%T\n", err.Error())}
}

2.使用fmt.Errorf()
fmt.Errorf()函数比errors.New()更灵活,它允许你使用格式化字符串来创建错误。这对于需要动态构建错误信息的场景非常有用。
package mainimport ("fmt"
)func main() {err := fmt.Errorf("错误代码: %d, 错误信息: %s", 1001, "操作失败")if err != nil {fmt.Println(err.Error())}
}

3. 综合案例
package mainimport ("errors""fmt"
)// 自己定义一个错误
// 1、errors.New("xxxxx")
// 2、fmt.Errorf()
// 都会返回 error 对象, 本身也是一个类型func main() {//根据用户传参数据,用我们定义好的函数处理age_err := setAge(-3)if age_err != nil {fmt.Println(age_err)}fmt.Printf("%T\n", age_err) // *errors.errorString//如果age_err为空,调用Error()方法会报错fmt.Printf("%T\n", age_err.Error()) // string// 方式二errInfo1 := fmt.Errorf("我是一个错误信息:%d\n", 500)//errInfo2 := fmt.Errorf("我是一个错误信息:%d\n", 404)if errInfo1 != nil {// 处理这个错误fmt.Println(errInfo1)fmt.Printf("%T\n", errInfo1.Error())}}// 设置年龄的函数,一定需要处理一些非正常用户的请求
// 返回值为 error 类型 这个是内置类型
// 作为一个开发需要不断思考的事情,代码的健壮性和安全性
func setAge(age int) error {if age < 0 {// 给出一个默认值age = 3// 抛出一个错误 errors 包return errors.New("年龄不合法")}// 程序正常的结果,给这个用户赋值fmt.Println("年龄设置成功:age=", age)//年龄合法,就返回nilreturn nil
}

(2)自定义错误类型(难点)
虽然errors.New()和fmt.Errorf()很方便,但在某些情况下,你可能需要更丰富的错误信息。这时,可以通过自定义类型来实现go内置的error接口。
自定义错误类型步骤
1、定义一个结构体
// JingTian 定义一个结构体
type JingTian struct {msg stringcode int
}
2、为该结构体创建个方法,实现go内置error接口中的Error方法
内置接口

// 注意,Error()方法开头大写 string
// 实现内置error接口的Error方法
// 注意,方法的调用者用指针类型,因为结构体是值类型,不同函数里面的操作是互相独立的
func (e *JingTian) Error() string {// fmt.Sprintf() 返回stringreturn fmt.Sprintf("错误信息:%s,错误代码:%d\n", e.msg, e.code)
}
3、创建个方法测试
// 使用错误测试
func test(i int) (int, error) {// 需要编写的错误if i != 0 {//自带的 errors.New()和fmt.Errorf() 只能返回字符串类型的错误信息,不常用,信息太少了// 更多的时候我们会使用自定义类型的错误//注意,返回的错误用内存地址,因为结构体是值类型return i, &JingTian{msg: "非预期数据", code: 500}}// 正常结果return i, nil
}
4、main方法中写逻辑
func main() {i, err := test(1)if err != nil {fmt.Println(err)//查看错误类型fmt.Printf("%T\n", err)ks_err, ok := err.(*JingTian)if ok {if ks_err.print() {// 处理这个错误中的子错误的逻辑}fmt.Println(ks_err.msg)fmt.Println(ks_err.code)}}fmt.Println(i)}
完整代码
package mainimport ("fmt"
)// JingTian 定义一个结构体
type JingTian struct {msg stringcode int
}// 注意,Error()方法开头大写 string
// 实现内置error接口的Error方法
// 注意,方法的调用者用指针类型,因为结构体是值类型,不同函数里面的操作是互相独立的
func (e *JingTian) Error() string {// fmt.Sprintf() 返回stringreturn fmt.Sprintf("错误信息:%s,错误代码:%d\n", e.msg, e.code)
}// 自定义错误,里面还可以写一些方法
// 处理error的逻辑
func (e *JingTian) print() bool {fmt.Println("hello,world")return true
}// 使用错误测试
func test(i int) (int, error) {// 需要编写的错误if i != 0 {//自带的 errors.New()和fmt.Errorf() 只能返回字符串类型的错误信息,不常用,信息太少了// 更多的时候我们会使用自定义类型的错误//注意,返回的错误用内存地址,因为结构体是值类型return i, &JingTian{msg: "非预期数据", code: 500}}// 正常结果return i, nil
}func main() {i, err := test(1)if err != nil {fmt.Println(err)//查看错误类型fmt.Printf("%T\n", err)ks_err, ok := err.(*JingTian)if ok {if ks_err.print() {// 处理这个错误中的子错误的逻辑}fmt.Println(ks_err.msg)fmt.Println(ks_err.code)}}fmt.Println(i)}

go语言中,业务逻辑其实代码量并不大,大多数是在处理错误逻辑
比如下购物商城代码:
购物
下单:
1、查询商品信息 (FindGoodsError: msg、code | fun-商品不在了 ,fun-商品失效 ,fun-网络错误 )
2、查询库存 (FindxxxError: msg、code | fun-库存为0 ,fun-库存>0)
3、查询物流是否可以到达 (xxxError: msg、code | fun ,fun)
4、查询价格生成订单 (xxxError: msg、code | fun ,fun)
5、支付成功与否 (xxxError: msg、code | fun ,fun)
6、成功就产生一个订单,推送到商家和物流 (xxxError: msg、code | fun ,fun)
2. Go语言的异常处理机制
panic 和 recover
与错误处理不同,Go语言中的异常处理是通过panic和recover关键字来实现的。panic用于表示程序中的严重错误,它会导致程序中断执行;recover用于捕获panic,并恢复程序的正常执行流程。
(1)使用panic
什么时候会发生恐慌panic,我们不知道什么时候会报错
程序运行的时候会发生panic
手动抛出panic。我们在一些能够预知到危险的情况下,可以主动抛出
panic可以接受任何类型的值作为参数,通常是一个字符串或错误对象,用于描述发生的异常。
使用 panic() 程序就会终止,停在这里强制结束
看下源码

package mainimport "fmt"func main() {panic("发生了异常")//panic后面的代码,程序不会执行fmt.Println("hello world")
}

在上面的例子中,程序会在执行到panic时中断,并打印出"发生了异常"这条消息。
如果有panic发生,我们尽可能接收它,并处理
出现了panic之后,如果panic语句前面有defer语句,先执行所有的defer语句。panic语句后面的defer语句不再执行
package mainimport "fmt"// panic recover
//
// 出现了panic之后,如果panic语句前面有defer语句,先执行所有的defer语句。
//
// defer : 延迟函数,倒序执行,处理一些问题。
func main() {defer fmt.Println("main--1")defer fmt.Println("main--2")fmt.Println("main--3")testPanic(1) // 外部函数,执行完panic之前的所有defer//后面的都不执行了defer fmt.Println("main--4")fmt.Println("main--5")
}
func testPanic(num int) {defer fmt.Println("testPanic--1")defer fmt.Println("testPanic--2")fmt.Println("testPanic--3")// 如果在函数中一旦触发了 panic,会终止后面要执行的代码。// 如果panic语句前面存在defer,正常按照defer逻辑执行。panic语句后面的defer语句不再执行if num == 1 {panic("出现预定的异常----panic")}defer fmt.Println("testPanic--4")fmt.Println("testPanic--5")
}

(2)使用recover
go 语言是追求简洁的,他没有使用 try…catch 语句
如果有些情况,必须要处理异常,就需要使用panic,抛出了异常,recover,接收这个异常来处理。
recover结合defer处理 panic 恐慌
recover必须在defer语句中调用,才能捕获到panic。defer语句会延迟函数的执行,直到包含它的函数即将返回时,才执行defer语句中的函数。
一般我们在某个函数抛出的panic,就在那个函数里面解决了
recover会返回panic的参数
recover返回任意类型

1. recover案例展示
package mainimport ("fmt"
)func main() {//defer语句绑定的匿名函数defer func() {r := recover()if r != nil {fmt.Println("捕获到异常:", r)}}()panic("发生了异常")fmt.Println("这行代码不会被执行")
}

在这个例子中,尽管在defer之后有panic调用,但defer中的函数仍然会执行,并捕获到panic抛出的异常。然后,程序会跳过panic之后的代码,继续执行defer之后的逻辑。
2. recover结合多个defer执行顺序
package mainimport "fmt"// panic recover
//
// 出现了panic之后,如果有defer语句,先执行所有的defer语句。
//
// defer : 延迟函数,倒序执行,处理一些问题。
func main() {defer fmt.Println("main--1")defer fmt.Println("main--2")fmt.Println("main--3")testPanic2(1) // 外部函数,如果在函数内部已经处理panic,那么程序会继续执行defer fmt.Println("main--4")fmt.Println("main--5")
}
func testPanic2(num int) {// 出去函数的时候处理这里面可能发生的panic// recover func recover() any 返回panic传递的值// panic func panic(v any)defer func() {if msg := recover(); msg != nil {fmt.Println("recover执行了... panic msg:", msg)// 处理逻辑fmt.Println("---------程序已恢复----------")}}()defer fmt.Println("testPanic--1")defer fmt.Println("testPanic--2")fmt.Println("testPanic--3")// 如果在函数中一旦触发了 panic,会终止后面要执行的代码。// 如果存在defer,正常按照defer逻辑执行if num == 1 {panic("出现预定的异常----panic")}defer fmt.Println("testPanic--4")fmt.Println("testPanic--5")
}

执行逻辑:
1、panic 触发
2、触发panic当前函数panic前面的所有defer语句,倒序执行
3、直到遇到recover处理了这个panic…函数结束
4、main,继续向下执行。
相关文章:
【Golang】深入解读Go语言中的错误(error)与异常(panic)
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
DMDSC更换DCR和VOTE磁盘
DMDSC更换DCR和VOTE磁盘 为了提高DMDSC集群运行速度和节点之间通信协调的效率,需要将运行在机械盘上的dcr和vote磁盘替换到SSD高效磁盘上。将原来200M的dcr和vote机械磁盘,换成500M的SSD高效磁盘。 磁盘替换规划信息如下所示: 信息说明 替…...
国产化框架PaddleYOLO结合Swanlab进行作物检测
1. 项目介绍 粮食安全,作为人类生存与发展的基石,始终是全球关注的焦点。它不仅仅关乎粮食的充足供应,更涉及粮食的质量安全、营养健康以及可持续生产等多个维度。在全球化、气候变化和资源环境约束日益加剧的背景下,如何确保粮食…...
Linux编译部署PHP环境
1.准备工作 安装前我们需要设置防护墙,开放端口,更新yum源 # 1.防火墙 systemctl status firewalld 看到active(running)就意味着防火墙打开了 systemctl stop firewalld 看到inactive(dead)就意味着防火墙关闭了 systemctl start fire…...
Win11禁止搜索栏查找互联网内容
禁止任务栏和开始菜单的搜索栏查找互联网内容的方法如下: 使用组策略:WinR键,或菜单框,输入gpedit.msc回车,启动本地组策略编辑器。使用左侧的边栏导航到“计算机配置”>“管理模板”>“Windows组件”>“搜索…...
dig和nmap的区别
dig和nmap是两种在网络管理和安全领域广泛使用的工具,它们在功能、用途和原理上存在显著差异。 dig 定义与功能: dig(Domain Information Groper)是一个用于查询DNS(域名系统)信息的命令行工具。它允许用…...
无人机飞手入伍当兵技术优势分析
随着现代战争形态的不断演变,无人机技术在军事领域的应用日益广泛,成为提升军队作战能力的重要手段。对于无人机飞手而言,其专业技能和实战经验在入伍当兵后能够转化为显著的技术优势,为国防事业贡献重要力量。以下是从专业技能优…...
[Everything] 文件搜索工具的下载及详细安装使用过程(附有下载文件)
快速搜索文件名及其所在路径 下载链接在文末 下载压缩包后解压 !!安装路径不要有中文 解压后得到文件 双击exe文件得到 选择简体中文,点击OK 点击“我接受” 更改安装目录,最好不要放在C盘,点击下一步 点击下一步 点…...
HIRI-ViT:使用高分辨率输入的视觉Transformer扩展
摘要 https://arxiv.org/pdf/2403.11999 视觉Transformer( V i T \mathrm{ViT} ViT)与卷积神经网络(CNN)的混合深度模型已成为视觉任务中一类强大的骨干网络。自然地,提高此类混合骨干网络的输入分辨率会增强模型容量…...
TI DSP TMS320F280025 Note15:串口SCI的使用
TMS320F280025 串口SCI的使用 ` 文章目录 TMS320F280025 串口SCI的使用框图分析串口特点可编程数据格式SCI端口中断非FIFO/FIFO模式下SCI中断的操作/配置UartDriver.cUartDriver.h串口时钟由PCLKCR7控制使能,默认位系统时钟4分频 串口接收与发送都可以触发中断 串口使用的引脚…...
[Bandzip] 文件解压工具的下载及详细安装使用过程(附有下载文件)
文件解压工具,避免解压出错,双击即可解压文件 下载链接在文末 下载压缩包后解压 !!安装路径不要有中文 解压得到文件 双击exe文件 同意并安装 安装完成后,点击关闭, 右键点击需要解压的压缩包࿰…...
微服务MongoDB解析部署使用全流程
目录 1、什么是MongoDB 1、非关系型数据库 2、非关系型数据库分类 3、MongoDB?bson格式什么样? 2、MongoDB的优势 3、MongoDB应用场景 4、术语 5、操作 1、安装MongoDB 1、查询镜像文件【不操作】 2、拉取镜像文件 3、创建数据挂载目录 4、启…...
string为什么存储在堆里
在 Java 中,字符串对象存储在堆内存中而不是栈内存中,这是由于 Java 的内存管理和对象生命周期的特性决定的。以下是详细解释: 1. Java 内存模型 Java 的内存模型主要分为以下几个部分: 堆(Heap)&#x…...
Python和C++及MATLAB距离相关性生物医学样本统计量算法及数据科学
🎯要点 统计观测值之间距离计算代谢组学和脂质组学分析相关距离矩阵计算卡方检验偏差校正快速计算距离协方差算法大规模生物系统分析距离矩阵相关性测试石油勘探统计学关系 Python距离矩阵 在数学、计算机科学,尤其是图论中,距离矩阵是一…...
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
文章目录 C模板进阶编程前言第一章: 非类型模板参数1.1 什么是非类型模板参数?1.1.1 非类型模板参数的定义 1.2 非类型模板参数的注意事项1.3 非类型模板参数的使用场景示例:静态数组的实现 第二章: 模板的特化2.1 什么是模板特化?2.1.1 模板…...
golang学习笔记20-面向对象(二):方法与结构体【重要】
本节内容是面向对象的核心与基础,很重要。 注意:由于导包语句已经在19讲(笔记19:面向对象的引入)展示过了,所以这里就不展示了。 一、方法的定义与细节 方法是与特定类型(通常是结构体&#x…...
广州C++信奥老师解一本通题 1919:【02NOIP普及组】选数
【题目描述】 已知nn个整数x1,x2,……xn 以及一个整数K(K<n)。从n个整数中任选K个整数相加,可分别 得到一系列的和。例如当n4, k3 4个整数分别为3,7,12,19 3, 7,12,19时,可得全部的组合与它们的和为: 371222 371929 7121938 3121934 现在,要求你计算出和为…...
cas5.3统一登录前后端分离改造方案(源码)
cas5.3 为什么选择cas5.3 版本 5.3 版本是最新的支持jdk8 的版本,并且项目架构基于maven ,商业项目中jdk8 仍是主流,在考虑商业收益的情况下,如果客户不要求,不会升级jdk, 基于Maven的项目比gradle 简单,…...
【ComfyUI】控制光照节点——ComfyUI-IC-Light-Native
原始代码(非comfyui):https://github.com/lllyasviel/IC-Light comfyui实现1(600星):https://github.com/kijai/ComfyUI-IC-Light comfyui实现2(500星):https://github.c…...
LVS+keepalived整合负载均衡配置
准备三台服务器;负载均衡服务器192.168.45.136,后端机器1,92.168.45.135,后端机器2,192.168.45.138 在两台后端机器上安装nginx服务,yum install -y nginx,并且启动nginx服务,systemctl start …...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
