Обработка ошибок Go, утверждение типа и сетевой пакет
Я учусь и пытаюсь понять, как получить более подробную информацию об ошибках из общего типа ошибки. Пример, который я буду использовать, - это сетевой пакет, в частности функция DialTimeout.
Подпись
func DialTimeout(network, address string, timeout time.Duration) (Conn, error)
Тип error определяет только функцию Error() string
. Если я хочу выяснить, почему DialTimeout не удалось, как я могу получить эту информацию? Я узнал, что могу использовать утверждение типа для получения конкретной ошибки net.Error
:
con, err := net.DialTimeout("tcp", net.JoinHostPort(address, "22"),
time.Duration(5) * time.Second)
if err != nil {
netErr, ok := err.(net.Error)
if ok && netErr.Timeout() {
// ...
}
}
но это только говорит мне, был ли у меня тайм-аут. Например, скажем, я хотел различать отказанное соединение и никакой маршрут к хосту. Как я могу это сделать?
Возможно, DialTimeout слишком высокоуровневый, чтобы дать мне такую деталь, но даже глядя на syscall.Connect, я не вижу как получить конкретную ошибку. Он просто говорит, что возвращает общий тип ошибки. Сравните это с Posix connect, который сообщит мне, почему он не прошел с различными кодами возврата.
Мой общий вопрос: как я должен вытащить данные об ошибке из общего типа error
, если документы golang не говорят мне, какие ошибки могут быть возвращены?
Ответы
Ответ 1
Большинство сетевых операций возвращают *OpError
, в котором содержится подробная информация об ошибке
и реализует интерфейс net.Error
. Поэтому для большинства случаев использования достаточно использовать net.Error
как вы уже это делали.
Но для вашего случая вы хотите утверждать, что возвращаемая ошибка была *net.OpError
и
используйте внутреннюю ошибку:
if err != nil {
if oerr, ok := err.(*OpError); ok {
// Do something with oerr.Err
}
}
Как только вы это сделаете, вы находитесь в зоне зависимости от платформы как системные вызовы под Linux
могут по-разному терпеть неудачу под Windows. Для Linux вы бы сделали что-то вроде этого:
if oerr.Err == syscall.ECONNREFUSED {
// Connection was refused :(
}
Пакет syscall
содержит важные константы ошибок для вашей платформы. К сожалению
сайт golang показывает только пакет syscall для Linux amd64. См. здесь для ECONNREFUSED
.
Поиск типов
В следующий раз вам интересно, что фактически возвращается какой-то функцией, и вы не можете сделать
головами и хвостами, попробуйте использовать формат %#v
, указанный в fmt.Printf
(и друзьях):
fmt.Printf("%#v\n", err)
// &net.OpError{Op:"dial", Net:"tcp", Addr:(*net.TCPAddr)(0xc20006d390), Err:0x6f}
Он напечатает подробную информацию о типе и, как правило, весьма полезен.