Подтвердить что ты не робот

Перейти: лить любое значение 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 в этом случае.

4b9b3361

Ответ 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