TGViewer
Cross Join - канал о разработке Cross Join - канал о разработке @crossjoin · 3.82K subscribers
Post #592 3.71K
Все знают, что ошибки в Go (всё время писать if err !=nil) - это путь страдания. Ладно, не все страдают, многим это нравится.

Но те, кто не слишком хорошо знаком с Go, могут сильно удивиться, если узнают, что проверить ошибку на nil тоже бывает не так-то просто.

Дело в том, что тип error в Go - это на самом деле интерфейс. Под такой интерфейс подойдёт любой тип, в котором есть метод Error(), возвращающий string. Утиная типизация.

Этим довольно часто пользуются, когда надо сохранить какие-то детали ошибки, а не только некое текстовое сообщение. Создают свою структуру, приделывают к ней метод Error(), и вуаля. Можно прозрачно её использовать в Go программе как обычную ошибку.


type CustomError struct {
When time.Time
What string
}

func (e *CustomError) Error() string {
return fmt.Sprintf("at %v, %s", e.When, e.What)
}


Однако есть нюанс. Функции обычно возвращают не конкретный тип, а интерфейс error. И для переменных, которые имеют тип интерфейс, Go в рантайме хранит там два значеня: тип и value.

Вот функция вернула интерфейс `error`, который внутри функции был *CustomError, тогда она вернула

1) тип (например, *CustomError)
2) value (собственно сам указатель)

В случае с неинициализированным указателем это будет

1) тип *CustomError
2) nil

И в этом случае if err != nil не пройдёт, потому что Go чувствует, что это не простой nil, а хитрожопый: там внутре задан какой-то тип. В итоге имеем такой прикол:


package main

import (
"fmt"
"time"
)

type CustomError struct {
When time.Time
What string
}

func (e *CustomError) Error() string {
return fmt.Sprintf("at %v, %s", e.When, e.What)
}

func DoSomething() error {
// неинициализированный указатель - это nil
var err *CustomError

if 2+2 == 5 {
return &CustomError{When: time.Now()}
}

return err // казалось бы, возвращаем nil
}

func main() {
err := DoSomething()

if err == nil {
fmt.Println("Нет ошибки")
} else {
fmt.Println("Есть ошибка")
}
}


получаем "Есть ошибка", хотя ошибки не было

В данном случае лучше возвращать простой nil, не типизированный, т.е. вместо return err написать return nil

И всё будет хорошо )

Cross Join - канал о разработке
Telegram Cross Join - канал о разработке Канал о разработке Антона Околелова. Разрабочик/ex-тимлид Go, живу в Чехии. Мысли, новости, вопросы. По вопросам рекламы @antonokolelov
  • ❤ 19
  • 😱 9
  • 👍 4
  • 👻 2
  • 😨 1
More from @crossjoin
  1. Sep 28, 2026Слышал недавно в каком-то подкасте мысль, что Haskell плохо подходит для вайбкодинга прост…
  2. Sep 26, 2026Антон Жиянов написал мини-книгу по Go-concurrency. Это что-то вроде плотного конспекта с и…
  3. Sep 22, 2026photo post
  4. Sep 14, 2026Поможем Руслану собрать фидбек. Проект некоммерческий 👆
  5. Sep 14, 2026AGBX (Agent Box) — небольшой open-source CLI для запуска Claude Code и Codex в изолированн…
  6. Sep 5, 2026Обалдеть, что творится. На Рейтерс вышла статья, в которой утверждается, что, помимо сканд…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →