Почему пользовательская переменная ошибки golang имеет несколько типов

я новый суслик и действительно запутался в типах переменных, если я определяю пользовательскую ошибку

    import (
        "fmt"
        "reflect"
    )

    // custom errors
    type myError struct {
        msg string
    }

    func (m *myError) Error() string {
        return m.msg
    }

    func errorGen() error {
        return &myError{"custom error"}
    }

сгенерировать новую ошибку и проверить ее тип

    func main() {
        e := errorGen()
        fmt.Println(reflect.TypeOf(e).Kind()) // type = pointer

        // first type assertion
        _, ok := e.(error)
        if ok {
            fmt.Println("type assertion error") // type = error
        }

        // second type assertion
        _, ok = e.(*myError)
        if ok {
            fmt.Println("type assertion *myError") // type = pointer
        }
    }

поэтому в приведенной выше переменной кода «e» одновременно отображаются 2 типа. Какой именно тип e? и почему «ошибка» - это интерфейс, а также может использоваться как возвращаемый тип?

большое спасибо

Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
Создание API ввода вопросов на разных языках программирования (Python, PHP, Go и Node.js)
API ввода вопросов - это полезный инструмент для интеграции моделей машинного обучения, таких как ChatGPT, в приложения, требующие обработки...
0
0
1 349
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

The Go Programming Language Specification

Errors

The predeclared type error is defined as

type error interface {
    Error() string
}

It is the conventional interface for representing an error condition, with the nil value representing no error.

Interface types

An interface type specifies a method set called its interface. A variable of interface type can store a value of any type with a method set that is any superset of the interface. Such a type is said to implement the interface.


e реализует заранее объявленный тип интерфейса error.

    // first type assertion
    _, ok := e.(error)
    if ok {
        fmt.Println("type assertion error") // type = error
    }

Конкретный тип e является указателем на тип myError.

    // second type assertion
    _, ok = e.(*myError)
    if ok {
        fmt.Println("type assertion *myError") // type = pointer
    }

Оба утверждения типа верны (ok есть true).

Ответ принят как подходящий

Вы должны различать «статический тип» и «динамический тип» переменной.

Каждая переменная в Go имеет именно статический тип один. Некоторые примеры:

  • После объявления a := 5 статическим типом a будет int, и это все, что нужно знать о a.
  • Статический тип e в вашем коде — error (потому что это то, что возвращает errorGen).
  • Вы можете указать статический тип следующим образом: var b uint16 = 9.

Теперь в Go есть типы интерфейсов. error - это такой тип интерфейса, см. ответ Питера. Некоторые переменные будут иметь error в качестве статического типа; ваш e является примером. Теперь вся цель переменной типа интерфейса состоит в том, чтобы хранить значения типов разные, которые реализуют этот интерфейс. Таким образом, переменная интерфейса, которая не равна нулю, каким-то образом «содержит» другую переменную (фактически значение). Тип этого содержащегося значения может быть любым, который реализует интерфейс. Тип содержащегося значения — «динамический тип». Утверждение типа позволяет извлекать значения этого динамического типа.

почему тип статистики e — error, а не pointer, учитывая, что errorGen возвращает адрес

zakaster 23.01.2019 08:43

Взгляните на errorGen func errorGen() error, он возвращает error. Возвращаемый тип — это тип в сигнатуре функции. Тело функции хранит *myError внутри ошибки, и эта ошибка возвращается. Тип возвращаемого значения функции определяется Только сигнатурой функции. Все, что вы пишете после return, не имеет значения для статического возвращаемого типа (до тех пор, пока он компилируется).

Volker 23.01.2019 08:59

Другие вопросы по теме