使用Golang中的类型断言检测值超出范围的错误
Given the following code:
iv, err := strconv.ParseInt("18446744073709551448", 10, 64)
fmt.Println(iv)
fmt.Printf("%#v
", err)
fmt.Printf("%v
", err)
//Output:
9223372036854775807
&strconv.NumError{Func:"ParseInt", Num:"18446744073709551448", Err:(*errors.errorString)(0x1040a040)}
strconv.ParseInt: parsing "18446744073709551448": value out of range
How can I detect that the function failed due to being out of range of an int64? The strconv.ParseInt function returns an error type, but in this case it is actually a strconv.NumError type as indicated by %#v
. The Error Handling and Go article mentions you can use type assertion to check for specific types of errors, but it doesn't give any examples. What expression should I use to complete this code:
if expression {
uv, err := strconv.ParseUint("18446744073709551448", 10, 64)
}
We have,
var ErrRange = errors.New("value out of range")
ErrRange indicates that a value is out of range for the target type.
type NumError struct { Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat) Num string // the input Err error // the reason the conversion failed (ErrRange, ErrSyntax) }
A NumError records a failed conversion.
func (e *NumError) Error() string
For example,
package main
import (
"fmt"
"strconv"
)
func main() {
iv, err := strconv.ParseInt("18446744073709551448", 10, 64)
if err != nil {
if numError, ok := err.(*strconv.NumError); ok {
if numError.Err == strconv.ErrRange {
fmt.Println("Detected", numError.Num, "as a", strconv.ErrRange)
return
}
}
fmt.Println(err)
return
}
fmt.Println(iv)
}
Output:
Detected 18446744073709551448 as a value out of range
The error that's returned from strconv.ParseInt
is only known at compile time to be some type that implements the Error interface. Type assertion allows you to insist that it's a strconv.NumError
and inspect its fields directly, but at the risk of throwing a runtime panic if you turn out to be wrong:
if err.(*strconv.NumError).Err.Error() == "value out of range" {
uv, err := strconv.ParseUint("18446744073709551448", 10, 64)
}
A more flexible solution (but maybe too loosey-goosey for your purposes) would be to perform a substring match on the err.Error()
method:
if strings.Contains(err.Error(), "value out of range") {
uv, err := strconv.ParseUint("18446744073709551448", 10, 64)
}