Как зарегистрировать ошибки утверждения типа в golang?

У меня есть массив некоторых данных, которые я хочу отобразить в []string. Я могу сделать это двумя способами:

a)

// someData
s := someData.([]string)

В этом случае выполнение будет остановлено после вывода ошибки на консоль.

b)

// someData
s, ok := someData.([]string)

В этом случае ошибок не возникнет, но s будет иметь нулевое значение.


Я хочу регистрировать ошибки в таких случаях отказа утверждения типа, не останавливая выполнение. Однако, когда я использую тип (b), я не вижу деталей ошибки.

Единственное решение, которое я могу придумать, это использовать reflect.TypeOf и печатать оба типа.

Есть ли другой способ получить ошибку при использовании решения (b)?


person Prateek    schedule 03.06.2016    source источник


Ответы (2)


Вы можете создать сообщение журнала самостоятельно. Нет необходимости в явных вызовах reflect, поскольку существует строка формата printf %T, которая создает тип.

s, ok := someData.([]string)
if !ok {
    log.Printf("got data of type %T but wanted []string", someData)
    ... handle the failure somehow
}

Не зная контекста, мне трудно составить полезную и информативную выписку журнала, но вы можете адаптировать эту идею в соответствии со своим вариантом использования.

person Paul Hankin    schedule 03.06.2016
comment
Удивительно, что golang не требует проверки правильности утверждения типа. Не может ли отсутствие проверки правильности утверждения типа привести к ошибкам времени выполнения? - person Kwestion; 12.09.2017
comment
@Kwestion значение ok говорит, действительно ли утверждение типа. - person Paul Hankin; 12.09.2017
comment
Правильно, и при работе с импортированными данными, такими как файл конфигурации или json, возможно, что при утверждении типов вы потерпите неудачу. Что произойдет, если ваше утверждение типа завершится ошибкой без проверки его достоверности? - person Kwestion; 12.09.2017

Что ж, в зависимости от того, как вы хотите выполнять утверждения типов, есть способ получить ошибки как в случае а), так и в случае б).

Итак, сначала я расскажу о b, потому что если это наиболее прямолинейно: вы можете использовать %T для получения типа элементов:

func typeAssert(i interface{}) []string {
    s, ok := i.([]string)
    if !ok {
        fmt.Printf("interface conversion: interface is %T, not []string\n", i)
    }
    return s
}

Другой способ включает восстановление после ошибки, поэтому вы можете получить паническое сообщение как ошибку:

func assertType(i interface{}) []string {

    // Recover
    defer func() {
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()

    return i.([]string)
}

func main() {
    assertType([]int{42})

    fmt.Println("Recovered from the error")
}
// OUTPUT:
// interface conversion: interface is []int, not []string
// Recovered from the error

Конечно, вы можете добавить свою собственную обработку ошибок, в зависимости от того, что вы хотите сделать. Первое решение в любом случае обеспечивает большую гибкость, но иногда recoverможет быть удобно (не обязательно в данном случае).

Вот ссылка на игровую площадку Go.

person T. Claverie    schedule 03.06.2016