Показаны сообщения с ярлыком утверждения типа (type assertions) в Go. Показать все сообщения
Показаны сообщения с ярлыком утверждения типа (type assertions) в Go. Показать все сообщения

суббота, 21 ноября 2020 г.

Go style guides: обертывание ошибок, обработка ошибок утверждения типа

Обертывание ошибок

Есть три основных варианта распространения ошибок в случае сбоя вызова:

  • Верните исходную ошибку, если нет дополнительного контекста для добавления и вы хотите сохранить исходный тип ошибки.
  • Добавьте контекст, используя "github.com/pkg/errors".Wrap, чтобы сообщение об ошибке предоставляло больше контекста и "github.com/pkg/errors".Cause можно использовать для извлечения исходной ошибки.
  • Используйте fmt.Errorf, если вызывающим абонентам не нужно обнаруживать или обрабатывать этот конкретный случай ошибки.

Рекомендуется добавлять контекст, где это возможно, чтобы вместо неопределенной ошибки, такой как "connection refused" ("соединение отклонено"), вы получали более полезные ошибки, такие как "call service foo: connection refused" ("вызов службы foo: соединение отклонено").

При добавлении контекста к возвращаемым ошибкам сохраняйте краткость контекста, избегая фраз вроде "failed to" ("не удалось"), которые констатируют очевидное и накапливаются по мере того, как ошибка просачивается через стек.

Менее удачный вариант:

s, err := store.New()
if err != nil {
    return fmt.Errorf("failed to create new store: %s", err)
}

Вывод:

failed to x: failed to y: failed to create new store: the error

Более удачный вариант:

s, err := store.New()
if err != nil {
    return fmt.Errorf("new store: %s", err)
}

Вывод:

x: y: new store: the error

Однако после отправки ошибки в другую систему должно быть ясно, что сообщение является ошибкой (например, тег err или префикс "Failed" в журналах).

Обработка ошибок утверждения типа

Форма единственного возвращаемого значения утверждения типа вызовет панику из-за неправильного типа. Поэтому всегда используйте идиому "comma ok".

Неудачный вариант:

t := i.(string)

Более удачный вариант:

t, ok := i.(string)
if !ok {
    // корректно обрабатываем ошибку
}


Читайте также:


пятница, 8 мая 2020 г.

Утверждение типа и переключатели типов в Golang

Утверждение типа (type assertion) обеспечивает доступ к конкретному значению интерфейса.

Утверждение типа на самом деле не преобразует интерфейс в другой тип данных, но обеспечивает доступ к конкретному значению интерфейса, которое обычно является тем, что вам нужно.

Утверждение типа x.(T) утверждает, что конкретное значение, хранящееся в x, имеет тип T, и что x не равно nil.

  • Если T не является интерфейсом, он утверждает, что динамический тип x идентичен T.
  • Если T является интерфейсом, он утверждает, что динамический тип x реализует T.

var x interface{} = "foo"

var s string = x.(string)
fmt.Println(s)     // "foo"

s, ok := x.(string)
fmt.Println(s, ok) // "foo true"

n, ok := x.(int)
fmt.Println(n, ok) // "0 false"

n = x.(int)        // ILLEGAL

panic: interface conversion: interface {} is string, not int

Переключатели типов

Переключатель типов (type switch) выполняет несколько утверждений типа последовательно и запускает первый случай с подходящим типом.

switch v := x.(type) {
case nil:
    fmt.Println("x is nil")            
case int: 
    fmt.Println("x is", v)             
case bool, string:
    fmt.Println("x is bool or string")
default:
    fmt.Println("type unknown")
}

Вывод:

x is bool or string


Читайте также:


пятница, 7 июня 2019 г.

Спецификация Go: утверждения типа (type assertions)

Для выражения x типа интерфейса и типа T первичное выражение

x.(T)

утверждает, что x не равен nil и что значение, хранящееся в x, имеет тип T. Обозначение x.(T) называется утверждением типа (type assertion).

Точнее, если T не является интерфейсным типом, x.(T) утверждает, что динамический тип x идентичен типу T. В этом случае T должен реализовать (interface) тип x; в противном случае утверждение типа недопустимо, поскольку для x невозможно сохранить значение типа T. Если T является типом интерфейса, x.(T) утверждает, что динамический тип x реализует интерфейс T.

Если утверждение типа выполнено, значением выражения является значение, сохраненное в x, а его типом является T. Если утверждение типа равно false, возникает паника во время выполнения. Другими словами, даже если динамический тип x известен только во время выполнения, тип x.(T) известен как T в правильной программе.

var x interface{} = 7    // x имеет динамический тип int и значение 7
i := x.(int)             // i имеет тип int и значение 7

type I interface { m() }

func f(y I) {
    s := y.(string)      // недопустимо: string не реализует I (пропущен метод m)
    r := y.(io.Reader)   // r имеет тип io.Reader и динамический тип y должен реализовывать оба I и io.Reader
    …
}

Утверждение типа, используемое в присваивании или инициализации специальной формы

v, ok = x.(T)
v, ok := x.(T)
var v, ok = x.(T)
var v, ok T1 = x.(T)

дает дополнительное нетипизированное логическое значение. Значение ok равно true, если утверждение верно. В противном случае оно равно false, а значение v является нулевым значением для типа T. В этом случае не возникает паника во время выполнения.


Читайте также: