Перейти: лить любое значение int для int64 в переключателе типа
У меня часто возникает ситуация, когда я ожидаю int
(любого типа, int/int8/16/32/64
) и проверяю его с помощью переключателя типа
switch t := v.(type) {
case int, int8, int16, int32, int64:
// cast to int64
case uint, uint8, uint16, uint32, uint64:
// cast to uint64
}
Теперь я не могу использовать прямой трансляции, потому что t
в этом случае будет иметь тип interface{}
. Действительно ли я должен разбить это на case
для каждого целочисленного типа?
Я знаю, что я мог бы сделать это через отражение с помощью reflect.ValueOf(v).Int()
, но не должен ли быть лучший (менее многословный) способ сделать это?
UPDATE:
Подал сбой, и Роб посоветовал просто использовать reflect
в этом случае.
Ответы
Ответ 1
Трудно дать вам мнение без контекста, но похоже, что вы пытаетесь сделать свою реализацию слишком универсальной, что характерно для людей, которые работали в основном с более динамическими языками или с общей поддержкой.
Часть процесса обучения Go учится охватывать систему своего типа, и в зависимости от того, откуда вы пришли, это может быть сложной задачей.
Обычно в Go вы хотите поддерживать один тип, который может содержать все возможные значения, которые необходимо обрабатывать. В вашем случае это, вероятно, будет int64.
Посмотрите, например, на математический пакет. Он работает только с int64 и ожидает, что кто-либо использует его, чтобы правильно его вывести, вместо того, чтобы пытаться преобразовать все.
Другой вариант - использовать интерфейс как агностик типа, как это делает пакет сортировки. В принципе, любой метод, специфичный по типу, будет реализован вне вашего пакета, и вы ожидаете, что определенные методы будут определены.
Требуется некоторое время, чтобы изучить и принять эти атрибуты, но в целом, в конце концов, это оказывается хорошим с точки зрения ремонтопригодности и надежности. Интерфейсы гарантируют, что у вас есть ортогональность и сильные типы, убедитесь, что вы контролируете преобразования типов, что в конечном итоге может вызвать ошибки и лишние копии в памяти.
Приветствия
Ответ 2
Какую проблему вы пытаетесь решить? Полное решение, которое вы описали, выглядит так:
func Num64(n interface{}) interface{} {
switch n := n.(type) {
case int:
return int64(n)
case int8:
return int64(n)
case int16:
return int64(n)
case int32:
return int64(n)
case int64:
return int64(n)
case uint:
return uint64(n)
case uintptr:
return uint64(n)
case uint8:
return uint64(n)
case uint16:
return uint64(n)
case uint32:
return uint64(n)
case uint64:
return uint64(n)
}
return nil
}
func DoNum64Things(x interface{}) {
switch Num64(x).(type) {
case int64:
// do int things
case uint64:
// do uint things
default:
// do other things
}
}
Ответ 3
Используйте reflect. Обратите внимание, что это, вероятно, будет намного медленнее, чем разворачивание коммутатора.
switch t := v.(type) {
case int, int8, int16, int32, int64:
a := reflect.ValueOf(t).Int() // a has type int64
case uint, uint8, uint16, uint32, uint64:
a := reflect.ValueOf(t).Uint() // a has type uint64
}
Ответ 4
Вы можете сделать что-то вроде этого... конвертировать в строку и затем анализировать строку. Не очень эффективный, но компактный. Я привел этот пример на игровой площадке Go: http://play.golang.org/p/0MCbDfUSHO
package main
import "fmt"
import "strconv"
func Num64(n interface{}) int64 {
s := fmt.Sprintf("%d", n)
i,err := strconv.ParseInt(s,10,64)
if (err != nil) {
return 0
} else {
return i
}
}
func main() {
fmt.Println(Num64(int8(100)))
fmt.Println(Num64(int16(10000)))
fmt.Println(Num64(int32(100000)))
fmt.Println(Num64(int64(10000000000)))
fmt.Println(Num64("hello"))
}
// Outputs:
// 100
// 10000
// 100000
// 10000000000
// 0