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…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
基于服务器使用 apt 安装、配置 Nginx
🧾 一、查看可安装的 Nginx 版本 首先,你可以运行以下命令查看可用版本: apt-cache madison nginx-core输出示例: nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
