Определите значение вне диапазона ошибок, используя утверждение типа в Golang

Учитывая следующий код:

iv, err := strconv.ParseInt("18446744073709551448", 10, 64)
fmt.Println(iv)
fmt.Printf("%#v\n", err)
fmt.Printf("%v\n", err)

//Output:
9223372036854775807
&strconv.NumError{Func:"ParseInt", Num:"18446744073709551448", Err:(*errors.errorString)(0x1040a040)}
strconv.ParseInt: parsing "18446744073709551448": value out of range

Как я могу определить, что функция не выполнена из-за выхода за пределы диапазона int64? Функция strconv.ParseInt возвращает тип ошибки, но в данном случае это фактически тип strconv.NumError, как указано %#v, В статье Обработка ошибок и Go упоминается, что вы можете использовать утверждение типа для проверки ошибок определенного типа, но в ней нет примеров. Какое выражение я должен использовать для завершения этого кода:

if expression {
    uv, err := strconv.ParseUint("18446744073709551448", 10, 64)
}

2 ответа

Решение

У нас есть,

Пакет strconv

var ErrRange = errors.New("value out of range")

ErrRange указывает, что значение выходит за пределы диапазона для целевого типа.

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)
}

NumError записывает неудачное преобразование.

func (e *NumError) Error() string

Например,

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)
}

Выход:

Обнаружено 18446744073709551448 как значение вне диапазона

Ошибка, которая возвращается из strconv.ParseInt известен только во время компиляции как некоторый тип, который реализует интерфейс Error. Утверждение типа позволяет утверждать, что это strconv.NumError и проверять его поля напрямую, но рискует вызвать панику во время выполнения, если вы ошибаетесь:

if err.(*strconv.NumError).Err.Error() == "value out of range" {
    uv, err := strconv.ParseUint("18446744073709551448", 10, 64)
}

Более гибким решением (но, возможно, слишком слабым для ваших целей) было бы выполнить сопоставление подстроки в err.Error() метод:

if strings.Contains(err.Error(), "value out of range") {
    uv, err := strconv.ParseUint("18446744073709551448", 10, 64)
}
Другие вопросы по тегам