七叶笔记 » golang编程 » 为什么Go的自定义error有时候会内存溢出

为什么Go的自定义error有时候会内存溢出

分享一个在go tour上看到的练习题,练习里要求用户自己定义一个错误类型,实现 error接口,函数在参数不满足条件的时候返回自定义的错误类型的值。练习中特别提示用户不要在实现的 Error方法里直接使用 fmt.Sprint(e)以避免造成程序内存溢出。

下面贴一下具体的练习题

Practice

从之前的练习中复制 Sqrt 函数,修改它使其返回 error 值。

Sqrt 接受到一个负数时,应当返回一个非 nil 的错误值。复数同样也不被支持。

创建一个新的类型

type ErrNegativeSqrt float64
 

并为其实现

func (e ErrNegativeSqrt) Error() string
 

方法使其拥有 error 值,通过 ErrNegativeSqrt(-2).Error() 调用该方法应返回 “cannot Sqrt negative number: -2″。

注意: 在 Error 方法内调用 fmt.Sprint(e) 会让程序陷入死循环。可以通过先转换 e 来避免这个问题:fmt.Sprint(float64(e))。这是为什么呢?

修改 Sqrt 函数,使其接受一个负数时,返回 ErrNegativeSqrt 值。

Solution

这里只为叙述返回error的情况,所以请忽略Sqrt函数的功能实现。

接下来探究一下为什么在练习中把值 e先转换为float64类型后程序就不会再内存溢出。

fmt.Sprint(e)将调用 e.Error()将 e转换为 字符串 。如果 Error()方法调用 fmt.Sprint(e),则程序将递归直到内存溢出。可以通过将 e转换成一个非错误类型(未实现Error接口)的值来避免这种情况。

实际上在 Error方法中把 error值直接传递给 fmt包中Print相关的函数都会导致无限循环。原因可以在fmt包的源码中找到。

通过链接可以在 Github 上看到这块详细的源码 #L639

这个练习感觉还是给开发者提示了一个非常隐蔽的坑,感兴趣的可以通过阅读原文的链接访问到go tour上的这个练习题自己试验一下。

喜欢本文的朋友,欢迎关注“Go语言中文网”:

本文作者:KevinYan11

原文链接:

相关文章