interface conversion: interface {} is uint64, not float32 - go

Basically I have map[interface{}]interface{} and inside under key "x" value 90 (I printed to confirm that data are correct), but when I do
mymap["x"].(float32)
I get error
interface conversion: interface {} is uint64, not float32
Problem is that I expect float number (produced from as output from another program). I also tried to float32(mymap["x"]) but not success(also tried examples from google with int64 without success).
I am using go version go1.10.1 linux/amd64

this is my script:
switch i := x.(type) {
case nil:
printString("x is nil") // type of i is type of x (interface{})
case int:
printInt(i) // type of i is int
case float64:
printFloat64(i) // type of i is float64
case func(int) float64:
printFunction(i) // type of i is func(int) float64
case bool, string:
printString("type is bool or string") // type of i is type of x (interface{})
default:
printString("don't know the type") // type of i is type of x (interface{})
}

Related

Cannot use type assertion on type parameter value

We can't use type assertions on generic typed variables. This seems like really strange behavior considering it's allowed by interface{}, but not by a generic constrained by interface{}. Wondering if there are any work arounds?
// This works
func isInt(x interface{}) bool {
_, ok := x.(int)
return ok;
}
// Compile Error
// invalid operation: cannot use type assertion on type parameter
// value x (variable of type T constrained by interface{})
func isInt2[T interface{}](x T) bool {
_, ok := x.(int)
return ok;
}
tl;dr
You can perform a type assertion only on interface values. So you must convert x to a valid interface type first, any / interface{} in this case:
func isInt[T any](x T) (ok bool) {
_, ok = any(x).(int) // convert, then assert
return
}
So why does this fail to compile?
_, ok = x.(int) // ... cannot use type assertion on type parameter value ...
x's type T is a type parameter, not an interface. It is only constrained by an interface. The Go (revised 1.18) language spec explicitly states type parameters are not allowed in a type assertion:
For an expression x of interface type, but not a type
parameter, and a type T ... the notation x.(T) is called a type assertion.
Also from from the generics tutorial on why parameter types need to be resolved at compile-time:
While a type parameter’s constraint typically represents a set of
types, at compile time the type parameter stands for a single type –
the type provided as a type argument by the calling code. If the type
argument’s type isn’t allowed by the type parameter’s constraint, the
code won’t compile.
This works.
func isInt[T interface{}](x T) bool {
_, ok := interface{}(x).(int)
return ok
}
Example on Go Playground:
https://go.dev/play/p/n_-Rdtx50ip

Go 1.18 Generics how to define a new-able type parameter with interface

This used to work in go1.18beta1, but not works in go1.18rc1
package main
type A struct{}
func (*A) Hello() {
println("Hello")
}
func Create[M any, PT interface {
Hello()
*M
}](n int) (out []*M) {
for i := 0; i < n; i++ {
v := PT(new(M))
v.Hello()
out = append(out, v)
}
return
}
func main() {
println(Create[A](2))
}
Execute will throw
./prog.go:16:21: cannot use v (variable of type PT constrained by interface{Hello(); *M}) as type *M in argument to append:
PT does not implement *M (type *M is pointer to interface, not interface)
Seems due to this limitation:
Embedding a type parameter, or a pointer to a type parameter, as an unnamed field in a struct type is not permitted. Similarly, embedding a type parameter in an interface type is not permitted. Whether these will ever be permitted is unclear at present.
How can I do this in go1.18rc1 ?
You have to convert v back to *M again.
out = append(out, (*M)(v))
The error you got is about assignability. In fact the quote in your question doesn't forbid embedding a pointer type in an interface . Both M and PT are different named type parameters and you can't assign one to the other without explicit conversion.
The conversion instead is valid because all types in PT’s type set (only *M) are convertible to *M.

How to correct type comparing in "if" construct

I try to use "reflect" and "(type)"
var a float64 = 6.0
if reflect.TypeOf(a) == float64 {
fmt.Printf("%T", a)
}
switch a.(type) {
case float64:
fmt.Printf("%T", a)
}
but both returned errors
error 1: type float64 is not an expression
error 2: cannot type switch on non-interface value a (type float64)
An if statement can only compare to a single type because it doesn't have branches like the switch statement, and you have to use a type assertion in an if statement like this:
var i interface{}
i = 3.3 // store a float64 value in i
if f, ok := i.(float64); ok {
fmt.Print("It's a float64 value: %.2f", f)
} else {
fmt.Println("Not float64")
}
This will output (try it on the Go Playground):
It's a float64 value: 3.30
You could use reflection too, but type assertion here is more efficient and more idiomatic. For reference, this is how using reflection would look like:
if reflect.TypeOf(i) == reflect.TypeOf(float64(0)) {
fmt.Printf("It's a float64 value: %.2f", i)
} else {
fmt.Println("Not float64")
}
Output is the same. Try this one on the Go Playground.
Note that when we used type assertion, we had a variable f of the asserted type (float64) so we could use it if some function would require a value of that type directly. When using reflection, we did not have a value of such type, i is "still" of type interface{}, we could use it because fmt.Printf() takes values of interface{}. But if we would have to pass it to a function that requires float64, we would still need to use (an additional) type assertion, like in the first example.
Also note that using type assertion and a type switch only makes sense if your input is an interface type, because only interface types may store values of different / multiple concrete types.
Using type assertion or type switch on a concrete type (like float64 value in your example) makes no sense becase that value may only be of type float64 and nothing else, so the language spec doesn't allow it in the first place.

Golang data as interface{} panics

Gophers,
I'm trying to implement the reflect package of Go and really stuck on one thing.
context - I'm trying to call an API that returns - time.Time and some data in interface{}. This data could be either int/int64 or float32/float64 for the most part. I take the data in interface{} and further create a struct where I keep the interface{} data in interface as reflect promises quite a few fancy things that I could do with the interface
type dataStore struct {
CreateTime time.Time
Data interface{}
}
I then create amap[string][]dataStore to store the data from the API that I fetch.
I'm trying to do the following to get the Float64 values that I know are coming and I want to do some math on them:
x := map[string][]dataStore {}
ReadDatafromAPI(x) // I call the API to read the data into variable x
//Assume map["CA"][]dataStore{{2020-03-31 21:55:52.123456, 123.4567890123e10},}
fmt.Println(x["CA"][0].Data) // This prints the data 123.4567890123e10, no problem
fmt.Println(reflect.ValueOf(x["CA"][0].Data))// this prints reflect.Value
va := reflect.ValueOf(x["CA"][0].Data)
fmt.Println(va.(float64)) // panic: interface conversion: interface {} is reflect.Value, not float64
fmt.Println(va.Interface()) // prints 123.4567890123e10
fmt.Println(va.Kind()) // prints struct
fmt.Println(va.NumField()) // prints 2 and I can fetch the fields using Field(0) and Field(1) -- the data doesn't make sense to me. not sure if those are pointers or what
I have just one objective - to fetch float64 as float64 and int as int. Meaning use reflect the way it is supposed to be used.
any insight would be highly appreciated.
Thanks in advance.
Folks - thanks for all the answers and pointers. I appreciate this! Looks like I still get reflect.Value as the type and not float64/32 as expected. See below:
switch flt := x["CA"][0].Data.(type) {
case float64:
fmt.Println("Data is float64 -> ", flt)
fmt.Printf("Type for flt is %T -> ", flt)
case float32:
fmt.Println("Data is float32 -> ", flt)
fmt.Printf("Type for flt is %T -> ", flt)
default:
fmt.Println("Its default!")
fmt.Printf("Type for flt is %T -> ", flt) // I always get here with reflect.Value as the Type. Never a float64 which is the value store without any question
}
if nflt, ok := x["CA"][0].Data.(float64); ok {
fmt.Println("nflt is float64")
} else {
fmt.Println("nflt is not float64) // I always get to Else
}
You don't need reflection to convert an interface to one of the known types. You need type assertions or a type switch:
if flt, ok:=data.(float64); ok {
// flt is float64
}
if i, ok:=data.(int); ok {
// i is int
}
Or:
switch k:=data.(type) {
case float64:
// Here, k is float64
case int:
// Here, k is int
}
Use a two-value type assertion to get the value without panicking:
d, ok := (x["CA"][0].Data.(float64)
if ok {
// it's a float64, do something with d.
}
or use a type switch:
switch d := x["CA"][0].Data.(type) {
case int:
// d is an int
case float64:
// d is a float64
... and other types as needed
default:
// handle unexpected type
}

Golang: cast an interface to a typed variable dynamically

In go, is it possible to cast variables dynamically somehow?
For example, if a simple cast would be:
var intAge = interfaceAge.(int)
What if I do not know that age is an int in advance? A simple way of writing it would be
var x = getType()
var someTypeAge = interfaceAge(.x)
Is there a way of achieving something like this? The reflect package gives some ways of determining or casting a type at runtime - but I couldn't find anything like the above mentioned (a generic scheme that would work for all types).
No you can't. Go is a static typed language. The type of a variable is determined at compile time.
If you want to determine dynamically the typeof an interface{} you could use type switching:
var t interface{}
t = functionOfSomeType()
switch t := t.(type) {
default:
fmt.Printf("unexpected type %T", t) // %T prints whatever type t has
case bool:
fmt.Printf("boolean %t\n", t) // t has type bool
case int:
fmt.Printf("integer %d\n", t) // t has type int
case *bool:
fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
case *int:
fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}

Resources