I often have a situation, where I expect an int
(of any type, int/int8/16/32/64
) and check for it using a type switch
switch t := v.(type) {
case int, int8, int16, int32, int64:
// cast to int64
case uint, uint8, uint16, uint32, uint64:
// cast to uint64
}
Now I cannot use a direct cast, because t
in this case will be of type interface{}
. Do I really have to split this up into case
s for each integer type?
I know that I could do it via reflection using reflect.ValueOf(v).Int()
, but shouldn't there be a better (less verbose) way of doing this?
UPDATE:
Filed an issue, and Rob advised to just use reflect
in this case.
It's hard to give you an opinion without more context but it looks like you're trying to make your implementation too generic, which is common from people that worked mostly with more dynamic languages or w/ generic support.
Part of the process of Learning Go is learning to embrace its type system, and depending on where you're coming from, it can be challenging.
Usually, in Go, you want to support one type that can hold all possible values you need to handle. In your case it would probably be a int64.
Take a look on the math package, for example. It only work with int64 and expect anyone using it to typecast it properly instead of trying to convert everything.
Another option is to use a interface to be type-agnostic, like the sort package does. Basically, any method that are type specific will be implemented outside of your package and you expect certain methods to be defined.
It takes a while to learn and accept these attributes but overall, in the end, it proves to be good in terms of maintainability and robustness. Interfaces ensure you have orthogonality and strong types makes sure you're in control of type conversions, which in the end can cause bugs and also unnecessary copies in memory.
Cheers
Use the reflect package. Notice that this is likely to be a lot slower than unrolling the switch.
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
}
What problem are you trying to solve? The full solution that you've described looks like this:
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
}
}
You could do something like this... convert to a string and then parse the string. Not really efficient but compact. I've put this example in the Go playground here: 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