為什麼Go中有的自定義error會導致記憶體溢位

2021-10-02 09:41:37 字數 2154 閱讀 4322

分享乙個在go tour上看到的練習題,練習裡要求使用者自己定義乙個錯誤型別,實現error介面,函式在引數不滿足條件的時候返回自定義的錯誤型別的值。練習中特別提示使用者不要在實現的error方法裡直接使用fmt.sprint(e)以避免造成程式記憶體溢位。

下面貼一下具體的練習題

從之前的練習中複製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值。

這裡只為敘述返回error的情況,所以請忽略sqrt函式的功能實現。

package main

import (

"fmt"

)type errnegativesqrt float64

func (e errnegativesqrt) error() string

func sqrt(x float64) (float64, error)

return 0, nil

}func main()

接下來**一下為什麼在練習中把值e先轉換為float64型別後程式就不會再記憶體溢位。

fmt.sprint(e)將呼叫e.error()e轉換為字串。如果error()方法呼叫fmt.sprint(e),則程式將遞迴直到記憶體溢位。可以通過將e轉換成乙個非錯誤型別(未實現error介面)的值來避免這種情況。

實際上在error方法中把error值直接傳遞給fmt包中print相關的函式都會導致無限迴圈。原因可以在fmt包的原始碼中找到。

switch verb {

case 'v', 's', 'x', 'x', 'q':

// is it an error or stringer?

// the duplication in the bodies is necessary:

// setting wasstring and handled, and deferring catchpanic,

switch v := p.field.(type) {

case error:

wasstring = false

handled = true

defer p.catchpanic(p.field, verb)

// 這裡呼叫了error方法

p.printfield(v.error(), verb, plus, false, depth)

return

通過鏈結可以在github上看到這塊詳細的原始碼

這個練習感覺還是給開發者提示了乙個非常隱蔽的坑,感興趣的可以去go tour上的這個練習題自己試驗一下。

課程推薦:簡明高效的go語言入門和實戰指南

Go 自定義排序

go語言包中包含了排序包 sort,其中針對一般的strings int型別已經有了排序方法 sort.ints a int sort.strings a string 1 分別實現三個函式 func p myslice len int func p myslice less i,j int boo...

Go 自定義排序

有的時候我們希望排序不是僅僅按照自然順序排序。例如,我們希望按照字串的長度來對乙個字串陣列排序而不是按照字母順序來排序。這裡我們介紹一下go的自定義排序。an highlighted block package main import sort import fmt 為了能夠使用自定義函式來排序,我...

為什麼Go的自定義error有時候會記憶體溢位

分享乙個在go tour上看到的練習題,練習裡要求使用者自己定義乙個錯誤型別,實現error介面,函式在引數不滿足條件的時候返回自定義的錯誤型別的值。練習中特別提示使用者不要在實現的error方法裡直接使用fmt.sprint e 以避免造成程式記憶體溢位。下面貼一下具體的練習題 從之前的練習中複製...