Тип литых пользовательских типов для базовых типов

Как преобразовать пользовательский тип в interface{}, а затем в базовый тип (например, uint8)?

Я не могу использовать прямой листинг, например uint16(val.(Year)), потому что я могу не знать все пользовательские типы, но я могу определять базовые типы (uint8, uint32,...) во время выполнения


Существует множество настраиваемых типов (обычно используемых как перечисление) на основе числовых:

Пример:

type Year  uint16
type Day   uint8
type Month uint8

и т.д.

Вопрос о литье типов от interface{} к базовым типам:

package main

import "fmt"

type Year uint16

// ....
//Many others custom types based on uint8

func AsUint16(val interface{}) uint16 {
    return val.(uint16) //FAIL:  cannot convert val (type interface {}) to type uint16: need type assertion
}

func AsUint16_2(val interface{}) uint16 {
    return uint16(val) //FAIL:   cannot convert val (type interface {}) to type uint16: need type assertion
}

func main() {
    fmt.Println(AsUint16_2(Year(2015)))
}

http://play.golang.org/p/cyAnzQ90At

Ответы

Ответ 1

Вы можете выполнить это, используя reflect:

package main

import "fmt"
import "reflect"

type Year uint16

func AsUint16(val interface{}) uint16 {
    ref := reflect.ValueOf(val)
    if ref.Kind() != reflect.Uint16 {
        return 0
    }
    return uint16(ref.Uint())
}

func main() {
    fmt.Println(AsUint16(Year(2015)))
}

В зависимости от вашей ситуации вы можете вернуть (uint16, error) вместо того, чтобы возвращать пустое значение.

https://play.golang.org/p/sYm1jTCMIf

Ответ 2

Почему вы включили Year в вопрос? Вы надеетесь преобразовать произвольные вещи в Years или преобразовать Years в uint16s?

Если я предполагаю, что вы имели в виду последний случай, тогда было бы лучше использовать метод

func (y Year) AsUint16() uint16 { 
    return uint16(y)
}

которому не нужны никакие утверждения или отражение типа.

https://play.golang.org/p/9wCQJe46PU