Go的自定义错误
在上一篇教程中,我们了解了 Go 中的错误表示以及如何处理标准库中的错误。我们还学习了如何从错误中提取更多信息。
本教程介绍如何创建我们自己的自定义错误,我们可以在函数和包中使用这些错误。我们还将使用标准库所采用的相同技术来提供有关自定义错误的更多详细信息。
使用 New 函数创建自定义错误
创建自定义错误的最简单方法是使用错误包的New函数。
在我们使用 New函数创建自定义错误之前,我们先了解一下它是如何实现的。下面提供了错误包中 New 函数的实现。
package errors// New returns an error that formats as the given text.
// Each call to New returns a distinct error value even if the text is identical.
func New(text string) error { return &errorString{text}
}// errorString is a trivial implementation of error.
type errorString struct { s string
}func (e *errorString) Error() string { return e.s
}
实现非常简单。errorString
是具有单个字符串字段的结构类型。该接口的Error() string
方法error
是使用第 1 4行中的errorString
指针接收器实现的。
第 5行中的New
函数。 接受一个string
参数,使用该参数创建一个errorString
类型的值并返回它的地址。因此,一个新的错误被创建并返回。
现在我们知道该New
函数是如何工作的,让我们在我们自己的程序中使用它来创建自定义错误。
我们将创建一个简单的程序来计算圆的面积,如果半径为负,则返回错误。
package mainimport ( "errors""fmt""math"
)func circleArea(radius float64) (float64, error) { if radius < 0 {return 0, errors.New("Area calculation failed, radius is less than zero")}return math.Pi * radius * radius, nil
}func main() { radius := -20.0area, err := circleArea(radius)if err != nil {fmt.Println(err)return}fmt.Printf("Area of circle %0.2f", area)
}
Run in playground
在上面的程序中,我们检查半径是否小于零。如果是这样,我们将返回nil
以及相应的错误消息。如果半径大于 0,则计算面积
在 main 函数中,我们检查错误是否不等nil
。 如果不是nil
,我们打印错误并返回,否则打印圆的面积。
在这个程序中,半径小于零,因此它将打印,
Area calculation failed, radius is less than zero
使用 Errorf 向错误添加更多信息
上面的程序运行良好,但如果我们打印导致错误的实际半径岂不是很好。这就是fmt包的Errorf函数派上用场的地方。该函数根据格式说明符格式化错误,并返回一个字符串作为接口的值。
让我们使用该Errorf
函数并使程序变得更好。
package mainimport ( "fmt""math"
)func circleArea(radius float64) (float64, error) { if radius < 0 {return 0, fmt.Errorf("Area calculation failed, radius %0.2f is less than zero", radius)}return math.Pi * radius * radius, nil
}func main() { radius := -20.0area, err := circleArea(radius)if err != nil {fmt.Println(err)return}fmt.Printf("Area of circle %0.2f", area)
}
Run in playground
在上面的程序中,运行该程序将输出,
Area calculation failed, radius -20.00 is less than zero
使用结构类型和字段提供有关错误的更多信息
还可以使用将错误接口实现为错误的结构类型。这为我们提供了错误处理的更大灵活性。在我们前面的示例中,如果我们想要访问导致错误的半径,现在唯一的方法就是解析错误描述Area calculation failed, radius -20.00 is less than zero
。这不是执行此操作的正确方法,因为如果描述发生更改,我们的代码就会中断。
我们将使用上一个教程中“将错误转换为基础类型并从结构体字段检索更多信息”部分中解释的标准库所遵循的策略,并使用结构体字段提供对导致错误的半径的访问。我们将创建一个实现错误接口的结构类型,并使用其字段来提供有关错误的更多信息。
第一步是创建一个结构类型来表示错误。错误类型的命名约定是名称应以文本结尾Error
。所以让我们将结构类型命名为areaError
type areaError struct { err stringradius float64
}
上面的结构类型有一个字段radius
存储导致错误的半径值,该err
字段存储实际的错误消息。
下一步是实现错误接口。
func (e *areaError) Error() string { return fmt.Sprintf("radius %0.2f: %s", e.radius, e.err)
}
在上面的代码片段中,我们Error() string
使用指针接收器实现了错误接口的方法。此方法打印半径和错误描述。
main
我们通过编写函数和函数来完成程序circleArea
。
package mainimport ( "errors""fmt""math"
)type areaError struct { err stringradius float64
}func (e *areaError) Error() string { return fmt.Sprintf("radius %0.2f: %s", e.radius, e.err)
}func circleArea(radius float64) (float64, error) { if radius < 0 {return 0, &areaError{err: "radius is negative",radius: radius,}}return math.Pi * radius * radius, nil
}func main() { radius := -20.0area, err := circleArea(radius)if err != nil {var areaError *areaErrorif errors.As(err, &areaError) {fmt.Printf("Area calculation failed, radius %0.2f is less than zero", areaError.radius)return}fmt.Println(err)return}fmt.Printf("Area of rectangle %0.2f", area)
}
Run in playground
在上面的程序中,circleArea
用于计算圆的面积。该函数首先检查半径是否小于零,如果是则使用导致错误的半径和相应的错误消息创建一个areaError
类型值,然后返回它的地址以及0
。因此,我们提供了有关错误的更多信息,在本例中是使用自定义错误结构的字段导致错误的半径。
如果半径不为负,该函数将计算并返回面积以及nil
我们试图求出半径为 -20 的圆的面积。由于半径小于零,因此将返回错误。
我们检查错误是否不等nil
我们尝试将其转换为*areaError
类型 。如果错误类型为\*areaError
,我们将在第 1 行中获取导致错误的半径。使用areaError.radius
,打印自定义错误消息并从程序返回。
如果错误不是类型*areaError
,我们只需在第 1 行打印错误并返回。如果没有错误,该将打印在数值
该程序将打印
Area calculation failed, radius -20.00 is less than zero
现在让我们使用上一篇教程中描述的第二种策略,并使用自定义错误类型的方法来提供有关错误的更多信息。
使用结构类型上的方法提供有关错误的更多信息
在本节中,我们将编写一个计算矩形面积的程序。如果长度或宽度小于零,该程序将打印错误。
第一步是创建一个结构来表示错误。
type areaError struct { err string //error descriptionlength float64 //length which caused the errorwidth float64 //width which caused the error
}
上面的错误结构类型包含一个错误描述字段以及导致错误的长度和宽度。
现在我们有了错误类型,让我们实现错误接口并在错误类型上添加几个方法以提供有关错误的更多信息。
func (e *areaError) Error() string { return e.err
}func (e *areaError) lengthNegative() bool { return e.length < 0
}func (e *areaError) widthNegative() bool { return e.width < 0
}
在上面的代码片段中,我们从方法返回错误的描述Error() string
。lengthNegative() bool
当长度小于零时,该方法返回 true;widthNegative() bool
当宽度小于零时,该方法返回 true。这两种方法提供了有关错误的更多信息,在这种情况下,它们表示面积计算是否由于长度为负或宽度为负而失败。因此,我们使用了结构错误类型的方法来提供有关错误的更多信息。
下一步是编写面积计算函数。
func rectArea(length, width float64) (float64, error) { err := ""if length < 0 {err += "length is less than zero"}if width < 0 {if err == "" {err = "width is less than zero"} else {err += ", width is less than zero"}}if err != "" {return 0, &areaError{err: err,length: length,width: width,}}return length * width, nil
}
上面的rectArea
函数检查长度或宽度是否小于零,如果是,则返回类型为 *areaError
的错误,否则返回带有nil
错误的矩形面积。
让我们通过创建 main 函数来完成这个程序。
func main() { length, width := -5.0, -9.0area, err := rectArea(length, width)if err != nil {var areaError *areaErrorif errors.As(err, &areaError) {if areaError.lengthNegative() {fmt.Printf("error: length %0.2f is less than zero\n", areaError.length)}if areaError.widthNegative() {fmt.Printf("error: width %0.2f is less than zero\n", areaError.width)}return}fmt.Println(err)return}fmt.Println("area of rect", area)
}
在 main 函数中,我们检查错误是否不等nil
,如果它不为nil,我们尝试将其转换为*areaError
类型。然后使用lengthNegative()
和widthNegative()
方法检查错误是否是由于长度为负或宽度为负而导致的。我们打印相应的错误消息并从程序返回。因此,我们使用错误结构类型上的方法来提供有关错误的更多信息。
如果没有错误,将打印矩形的面积。
这是完整的程序供您参考。
package mainimport ( "errors""fmt"
)type areaError struct { err string //error descriptionlength float64 //length which caused the errorwidth float64 //width which caused the error
}func (e *areaError) Error() string { return e.err
}func (e *areaError) lengthNegative() bool { return e.length < 0
}func (e *areaError) widthNegative() bool { return e.width < 0
}func rectArea(length, width float64) (float64, error) { err := ""if length < 0 {err += "length is less than zero"}if width < 0 {if err == "" {err = "width is less than zero"} else {err += ", width is less than zero"}}if err != "" {return 0, &areaError{err: err,length: length,width: width,}}return length * width, nil
}func main() { length, width := -5.0, -9.0area, err := rectArea(length, width)if err != nil {var areaError *areaErrorif errors.As(err, &areaError) {if areaError.lengthNegative() {fmt.Printf("error: length %0.2f is less than zero\n", areaError.length)}if areaError.widthNegative() {fmt.Printf("error: width %0.2f is less than zero\n", areaError.width)}return}fmt.Println(err)return}fmt.Println("area of rect", area)
}
Run in playground
该程序将打印输出,
error: length -5.00 is less than zero
error: width -9.00 is less than zero
我们已经看到了错误处理教程中描述的三种方法中的两种的示例,以提供有关错误的更多信息。
使用直接比较的第三种方法非常简单。我将把它作为一个练习,让您了解如何使用此策略来提供有关我们的自定义错误的更多信息。
祝你有美好的一天。
相关文章:
Go的自定义错误
在上一篇教程中,我们了解了 Go 中的错误表示以及如何处理标准库中的错误。我们还学习了如何从错误中提取更多信息。 本教程介绍如何创建我们自己的自定义错误,我们可以在函数和包中使用这些错误。我们还将使用标准库所采用的相同技术来提供有关自定义错…...

SpringBoot集成Dubbo
在SpringMVC中Dubbo的使用https://tiantian.blog.csdn.net/article/details/134194696?spm1001.2014.3001.5502 阿里巴巴提供了Dubbo集成SpringBoot开源项目。(这个.....) 地址GitHub https://github.com/apache/dubbo-spring-boot-project 查看入门教程 反正是pilipala一大…...

利用shp文件构建mask【MATLAB和ARCGIS】两种方法
1 ARCGIS (推荐!!!-速度很快) 利用Polygon to Raster 注意:由于我们想要的mask有效值是1,在进行转换的时候,注意设置转换字段【Value field】 【Value field】通过编辑shp文件属性表…...

Luminar Neo Mac/Windows中文版:引领AI图像编辑的革命性时代
Luminar Neo运用先进的AI技术,能够自动化地完成许多繁琐的编辑任务,如色彩校正、噪点消除、人脸识别等。这不仅大大提高了工作效率,同时也降低了对专业知识和技能的要求。无论你是专业摄影师,还是摄影爱好者,甚至是一个…...

远程设备常用工具:向日葵、Todesk
其实按理说远程工具例如向日葵、Todesk如果是计算机专业、计算机从业者是必须知道的一个东西,但是在大学期间身边知道的人是少之又少的。 向日葵、Todesk工具的优势:方便、快捷、速度快等等我就不过多阐述了 PS:现在我就是在学校用远程写这篇 很多时候…...
JAVA七种常见排序算法
前言: 排序算法在计算机科学中扮演着至关重要的角色,它们用于将无序数据变为有序数据,以便更有效地检索和处理信息。不同的排序算法适用于不同的情况,因此了解它们的工作原理和性能特点对于选择正确的算法至关重要。本文提供的Jav…...

高质量绝世玄幻小说,情节引人入胜,一读成痴的绝佳选择
《我有一个修仙世界》 在这个高科技后修仙时代,主角拥有资源丰富的原始修仙世界。他需要不断地探索、发掘、修炼,才能成为真正的修仙者。这是一本充满想象力和创意的小说。 《长生武道:从五禽养生拳开始》 林轩修炼养生类功法,通过…...
Flask三种添加路由的方法
Flask 是一个流行的 Python Web 框架,它提供了多种方法来添加路由。路由是将 URL 映射到特定函数的过程,它是构建 Web 应用程序的基础。本文将介绍 Flask 中几种常用的路由添加方法,并附带代码示例。 方法一:使用装饰器 from flas…...
基于layui的select选择框修改为多选框
layui-xm-select 的功能强大,可多选、可下拉树、下拉日期多选、下拉折叠面板、下拉穿梭框、级联模式。 首先在引用layui css和js 的基础上,再引用js:layui-xm-select layui-xm-select点击下载地址 基本使用 第一步: 下载 第二步: 引入 layu…...

【技术分享】RK356X Android 使用 libgpiod 测试gpio
前言 libgpiod 是用于与 Linux GPIO 字符设备交互的 C 库和工具库;此项目包含六种命令行工具(gpiodetect、gpioinfo、gpioset、gpioget、gpiomon),使用这些工具可以在命令行设置和获取GPIO的状态信息;在程序开发中也可…...
代碼隨想錄算法訓練營|第五十九天|647. 回文子串、7516.最长回文子序列、动态规划总结篇。刷题心得(c++)
目录 讀題 647. 回文子串 看完代码随想录之后的想法 516.最长回文子序列 看完代码随想录之后的想法 647. 回文子串 - 實作 思路 動態規劃思路 雙指針思路 Code 動態規劃思路 雙指針思路 516.最长回文子序列 - 實作 思路 Code 动态规划 - 總結 動態規劃基礎 動…...

Qt封装的Halcon显示控件,支持ROI绘制
前言 目前机器视觉ROI交互控件在C#上做的比较多,而Qt上做的比较少,根据作者 VSQtHalcon——显示图片,实现鼠标缩放、移动图片的文章,我在显示和移动控件的基础上,增加了ROI设置功能,并封装成了一个独立的Q…...

基于深度学的图像修复 图像补全 计算机竞赛
1 前言 🔥 优质竞赛项目系列,今天要分享的是 基于深度学的图像修复 图像补全 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐! 🧿 更多资料, 项目分享: https://gitee.com/dancheng-se…...

vue3框架全局修改样式(字体颜色以及初始化定义基础elemplent颜色)
问题1、全局修改vue管理系统框架的字体颜色(index.scss目录下修改) 问题2、vue3中使用elemplent-plus中的el-select组件,默认选中二级或三级的一个数据,没有显示label只显示了id 问题如下 原因是因为 这个属性为true了࿰…...

Linux - 进程控制(上篇)- 进程创建 和 进程终止
进程控制 进程创建 对于进程的创建,你肯定知道,在 C/C 当中使用 fork()函数,以当前可执行程序生成的进程为 父进程,创建这个父进程的 一个子进程,这个 子进程就是一个新的进程。 如上图所示&a…...

NiceGui:Python中的轻量级GUI框架初体验
目录 一、引言 二、NiceGui概述 三、NiceGui实战:一个简单的计算器应用 四、NiceGui与其他GUI框架的比较 五、注意事项 总结与展望 一、引言 Python作为一门功能强大且易于学习的编程语言,广泛应用于各种领域。在图形用户界面(GUI&…...
php 常用的接口和函数
ArrayAccess — interface to provide accessing to objects as arrays 提供以数组形式访问对象的接口。 interface synopsis 接口需要实现下面几个方法 interface ArrayAccess { /* Methods */ public offsetExists(mixed $offset): bool public offsetGet(mixed $offset):…...
【Flutter】Flutter 动画深入解析(2):掌握 AnimatedBuilder 将动画的逻辑和 UI 代码分离
【Flutter】Flutter 动画深入解析(2):掌握 AnimatedBuilder 将动画的逻辑和 UI 代码分离 文章目录 一、前言二、Flutter 动画简介三、什么是 AnimatedBuilder四、AnimatedBuilder 与其他动画小部件的比较五、如何使用 AnimatedBuilder六、实际业务中的应用场景七、完整示例八…...

Spring Boot中解决跨域问题(CORS)
1. 跨域介绍 首先解释什么是跨域,跨域就是前端和后端的端口号不同;会产生跨域问题,这里浏览器的保护机制(同源策略)。 同源策略:前端和后端的协议、域名、端口号三者都相同叫做同源。 我们看一下不同源&am…...

基于生成对抗网络的照片上色动态算法设计与实现 - 深度学习 opencv python 计算机竞赛
文章目录 1 前言1 课题背景2 GAN(生成对抗网络)2.1 简介2.2 基本原理 3 DeOldify 框架4 First Order Motion Model5 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 基于生成对抗网络的照片上色动态算法设计与实现 该项目较为新颖&am…...

国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...