#go
# #Вперед
Вопрос:
Я играю с Go Playground и нахожу этот код:
package main
import (
"fmt"
"time"
)
type MyError struct {
When time.Time
What string
}
func (e *MyError) Error() string {
return fmt.Sprintf("at %v, %s",
e.When, e.What)
}
func run() error {
return amp;MyError{
time.Now(),
"it didn't work",
}
}
func main() {
if err := run(); err != nil {
fmt.Println(err)
}
}
Итак, здесь я вижу, что *MyError
реализует error
интерфейс. Однако, если я удаляю amp;
in error
func и возвращаю MyError
вместо этого, я получаю ошибку времени компиляции:
prog.go:19: cannot use MyError literal (type MyError) as type error in return argument: MyError does not implement error (Error method has pointer receiver)
. ХОРОШО, я могу это понять, поэтому я могу создать Error
такую функцию, и она будет успешно скомпилирована и запущена:
func (e MyError) Error() string {
return fmt.Sprintf("at %v, %s",
e.When, e.What)
}
func run() error {
return MyError{
time.Now(),
"it didn't work",
}
}
Затем я вижу в main
func, что есть проверка, если err
это nil
так, если я правильно понимаю error
nil
, в некоторых ситуациях вполне возможно, что функция возвращается. Таким образом MyError
, struct может принимать nil
значения. Но тогда, если я попытаюсь скомпилировать это:
import (
"fmt"
"time"
)
type MyError struct {
When time.Time
What string
}
func (e MyError) Error() string {
return fmt.Sprintf("at %v, %s",
e.When, e.What)
}
func run() error {
return nil
return MyError{
time.Now(),
"it didn't work",
}
}
func main() {
var err2 MyError = nil
fmt.Println(err2)
if err := run(); err != nil {
fmt.Println(err)
}
}
компилятор go сказал, что: prog.go:27: cannot use nil as type MyError in assignment
[process exited with non-zero status]
Почему в верхнем регистре компиляция проходит успешно, а в этом случае компиляция завершается неудачно? Возможно ли, чтобы структуры были nil
(я думаю, нет, но тогда почему run
функция компилируется?)
Ответ №1:
В первом примере *MyError
реализован error
интерфейс. Как вы можете видеть, это указатель, а указатель может иметь nil
значение.
var err *MyError
err == nil // true
var err *MyError = new(MyError)
err == nil // false
Но во втором примере это MyError
то, что реализует error
интерфейс, и это больше не указатель.
var err MyError
err == MyError{} // true
amp;err == nil // false
err == nil // Compilation error
Это может быть адрес err
этого времени nil
, а не сама переменная.
В качестве сравнения рассмотрим int
тип: var i int
. Вы можете проверить i == 0
, например, но было бы ошибкой проверять, если i == nil
, потому nil
что не является целым числом (точно так же, как это не было MyError
раньше). Но вы все равно можете проверить, является ли адрес i
nil
: amp;i == nil
.
Редактировать
Имейте в виду, что эта функция всегда будет возвращаться nil
(выполнение останавливается сразу после первого return
):
func run() error {
return nil
return MyError{
time.Now(),
"it didn't work",
}
}
Он компилируется, потому что прототип функции сообщает, что она должна возвращать значение an error
и действительно nil
является допустимым error
, как и MyError{}
переменная. Но попробуйте изменить этот прототип функции на этот:
func run() MyError
Вы увидите, что компиляция завершается с ошибкой, потому nil
что не является MyError
переменной, даже если это допустимое значение для error
типа.
Комментарии:
1. Я понимаю это, но посмотрите на
run
функцию. Он возвращает MyError, но также может возвращать nil .2. Ага, теперь это имеет смысл. Спасибо вам.
![]()
Ответ №2:
Интерфейс с нулевым значением — это не то же самое, что интерфейс, содержащий нулевое значение.
В вашем вопросе вы видели, что интерфейс (в вашем случае встроенный интерфейс ошибок) может быть nil , и сделали неверный вывод о том, что каждый тип, который может реализовать интерфейс, также может быть nil.