я новый суслик и действительно запутался в типах переменных, если я определяю пользовательскую ошибку
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? и почему «ошибка» - это интерфейс, а также может использоваться как возвращаемый тип?
большое спасибо
The Go Programming Language Specification
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.
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
является примером. Теперь вся цель переменной типа интерфейса состоит в том, чтобы хранить значения типов разные, которые реализуют этот интерфейс. Таким образом, переменная интерфейса, которая не равна нулю, каким-то образом «содержит» другую переменную (фактически значение). Тип этого содержащегося значения может быть любым, который реализует интерфейс. Тип содержащегося значения — «динамический тип».
Утверждение типа позволяет извлекать значения этого динамического типа.
Взгляните на errorGen func errorGen() error
, он возвращает error
. Возвращаемый тип — это тип в сигнатуре функции. Тело функции хранит *myError внутри ошибки, и эта ошибка возвращается. Тип возвращаемого значения функции определяется Только сигнатурой функции. Все, что вы пишете после return
, не имеет значения для статического возвращаемого типа (до тех пор, пока он компилируется).
почему тип статистики e —
error
, а неpointer
, учитывая, чтоerrorGen
возвращает адрес