负数检测 – 永夜 https://www.shuijingwanwq.com 没有不值得去解决的问题,也没有不值得去学习的技术! Sat, 16 May 2026 10:59:09 +0000 zh-Hans hourly 1 https://wordpress.org/?v=7.0 Go 语言进阶:深入理解自定义 Error 接口与无限递归陷阱 https://www.shuijingwanwq.com/2026/04/23/9572/ https://www.shuijingwanwq.com/2026/04/23/9572/#respond Thu, 23 Apr 2026 03:37:07 +0000 https://www.shuijingwanwq.com/?p=9572 浏览量: 162

在 Go 语言中,错误(Error)不是一种异常,而是一种值。通过实现 error 接口,我们可以创建具有丰富上下文信息的自定义错误类型。本文将结合 Go Tour 的 “Exercise: Errors” 练习,探讨如何实现一个支持负数检测的平方根函数,并揭示其中容易踩中的“无限递归”坑。

一、核心需求分析

我们需要完成以下任务:

* 定义一个自定义错误类型 ErrNegativeSqrt。

* 为该类型实现 Error() string 方法,使其满足 error 接口。

* 修改 Sqrt 函数,当输入为负数时返回该自定义错误。

二、代码实现

定义自定义错误类型

我们首先定义一个基于 `float64` 的新类型:

type ErrNegativeSqrt float64

实现 Error 接口

这是本练习最关键的部分。我们需要让 ErrNegativeSqrt 实现 error 接口:

func (e ErrNegativeSqrt) Error() string {
    return fmt.Sprintf("cannot Sqrt negative number: %v", float64(e))
}

> ⚠️ 避坑指南:为什么必须转换 `float64(e)`?
> 如果你在 Error() 方法中直接写 `fmt.Sprint(e)`,程序会陷入 无限递归。
> 原因:`fmt.Sprint` 在打印变量时,如果发现该变量实现了 error 接口,它会优先调用其 Error() 方法。
> 结果:Error() 调用 `fmt.Sprint` -> `fmt.Sprint` 再次调用 Error() -> 死循环。
> 解决:通过 `float64(e)` 将类型转换为基本类型,打破这个调用链。

完善 Sqrt 函数

利用标准库 `math.Sqrt` 并加入错误检查逻辑:

package main

import (
	"fmt"
	"math"
)

// ErrNegativeSqrt 自定义错误类型
type ErrNegativeSqrt float64

// Error 实现 error 接口
// 注意:必须将 e 转换为 float64(e),否则 fmt.Sprint(e) 会再次调用 Error() 方法,导致无限递归
func (e ErrNegativeSqrt) Error() string {
	return fmt.Sprintf("cannot Sqrt negative number: %v", float64(e))
}

// Sqrt 计算平方根,如果输入为负数则返回错误
func Sqrt(x float64) (float64, error) {
	if x < 0 {
		return 0, ErrNegativeSqrt(x)
	}
	return math.Sqrt(x), nil
}

func main() {
	fmt.Println(Sqrt(2))
	fmt.Println(Sqrt(-2))
}

三、运行结果 执行 main 函数后,输出如下:

/app/go-tour/exercise-errors # go run main.go 
1.4142135623730951 &lt;nil>
0 cannot Sqrt negative number: -2

四、总结
通过这个简单的练习,我们学到了:
1. 接口的隐式实现:只要定义了 Error() string 方法,任何类型都可以成为 error。
2. 错误即数据:我们可以像处理普通结构体一样,在错误中携带额外的字段(如本例中的数值)。
3. 格式化细节:在使用 `fmt` 包处理实现了自身接口的类型时,需注意类型转换以避免递归。

]]>
https://www.shuijingwanwq.com/2026/04/23/9572/feed/ 0