golang, create a variable from another one - go

I want to :
Create a variable with the type of another one. The source variable is numeric (int, int16, float32, ...)
Make some simple operations (+, -, ...) on this variable.
This code works fine :
package main
import (
"fmt"
"reflect"
)
func init1(v interface{}) interface{} {
switch reflect.ValueOf(v).Kind() {
case reflect.Int:
return int(0)
case reflect.Float32:
return float32(0)
case reflect.Float64:
return float64(0)
}
return nil
}
func sum(x, y interface{}) interface{} {
switch reflect.ValueOf(x).Kind() {
case reflect.Int:
return x.(int) + y.(int)
case reflect.Float32:
return x.(float32) + y.(float32)
case reflect.Float64:
return x.(float64) + y.(float64)
}
return nil
}
func main() {
v0 := 222.33
x0 := init1(v0)
x0 = sum(x0, v0)
x0 = sum(x0, v0)
fmt.Printf("v=%v, x=%v type x=%T\n", v0, x0, x0)
v1 := 33
x1 := init1(v1)
x1 = sum(x1, v1)
x1 = sum(x1, v1)
fmt.Printf("v=%v, x=%v type x=%T\n", v1, x1, x1)
}
Result :
v=222.33, x=444.66 type x=float64
v=33, x=66 type x=int
Is there a more elegant solution (without the two switch blocks) to do the same job ?
Thanks for your help.

Is there a more elegant solution (without the two switch blocks) to do the same job ?
No there is not.
You could use reflection but would still need a switch for int, uints and floats.
(Btw: Don't do such things.)

There is more elegant and more effective solution - do not use interface{} as casting to/from interface{} will result in spending resources (CPU/memory) on boxing/unboxing.
// Bad solution - 11 lines of slow code
func sumBad(x, y interface{}) interface{} {
switch reflect.ValueOf(x).Kind() {
case reflect.Int:
return x.(int) + y.(int)
case reflect.Float32:
return x.(float32) + y.(float32)
case reflect.Float64:
return x.(float64) + y.(float64)
}
return nil
}
// Good solution - 9 lines of code that works faster
func sumInt(a, b int) int {
return a + b
}
func sumFloat32(a, b float32) float32 {
return a + b
}
func sumFloat64(a, b float64) float64 {
return a + b
}
If you have much more code inside the function you can use Go code generation to generate the functions for as many types as you want.
Another alternative would be to choose a type that cover all your needs. For example can you use just float64 and cast parameters to it whenever needed?

Related

Operate on a struct with lots of pointers (especially to numbers)

I have quite a few data structures that contain mostly numbers, I get the data, do a calculation and return the result.
The thing is that all of those numbers can be zero and hence, I had to switch to using pointers (*int64 or *float64) so that the default is nil and not 0.
Unfortunately, I don't know of a solution to this in Go except using pointers.
The problem comes now in the Calculate() function that is implemented for all data structures:
type X struct {
A, B, C, D, E, F *int
// and much more
Result *float64
}
func (x *X) Calculate() {
floatptr := func(f float64) *float64 { return &f }
x.Result = floatptr(float64(*x.A + *x.B + *x.C + *x.D + *x.E + *x.F))
}
This function will obviously panic if any of the data is nil. So, I wrote the functions differently that it checks for nil data before the calculation:
func (x *X) CalculateWithNilChecks() {
floatptr := func(f float64) *float64 { return &f }
if x.A == nil || x.B == nil || x.C == nil || x.D == nil || x.E == nil || x.F == nil {
return
}
x.Result = floatptr(float64(*x.A + *x.B + *x.C + *x.D + *x.E + *x.F))
}
The problem is that the data structures are quite long. Having a SUPER long if x != nil looks ugly. I was wondering if there is another (cleaner) way to doing this.
I thought of doing like in the encoding/json and just recover nil pointer dereference panics, not sure if this is cleaner TBH.
Another thought was to reflect the data structures and stop if any of the required data is nil, I don't think this should be necessary for such a simple task.
Here is a playground link for the above code
What am I missing here? Thanks!
As general solution you can unmarshal your JSON into a map of *int pointers or json.RawMessage and then use a reflection to cross check with your struct or just check it with expected number of fields.
func main() {
result := make(map[string]*int)
str := `{ "A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "F": 6 }`
json.Unmarshal([]byte(str), &result)
for _, field := range result {
// Check if expect fields exists using reflection or manually
// ...
}
}
You can use reflect module and error when one of the required fields is missing.
Use this as template.
package main
import (
"fmt"
"reflect"
)
type X struct {
A, B, C, D, E, F *int
Result *float64
}
func (x *X) PrintFoo() {
fmt.Println(x.A)
}
func main() {
a := 3
x := X{A: &a}
val := reflect.ValueOf(x)
for i := 0; i < val.Type().NumField(); i++ {
field := val.Type().Field(i)
fieldType := fmt.Sprintf("%s", field.Type)
if fieldType == "*int" && val.FieldByName(field.Name).IsNil() {
fmt.Println("Missing value on field", field.Name)
}
}
}

Go error checking and chaining

package main
import (
"errors"
"fmt"
)
type FieldElement struct {
Num int
Prime int
}
func (el *FieldElement) Add(o FieldElement) (FieldElement, error) {
if el.Prime != o.Prime {
return FieldElement{}, errors.New("cannot operate on two numbers in different Fields")
}
return FieldElement{(el.Num + o.Num) % el.Prime, el.Prime}, nil
}
// Sub, Mul, Div and Pow also members of FieldElement returning (FieldElement, error)
func main() {
a := FieldElement{13, 19}
b := FieldElement{9, 19}
fmt.Println(a.Add(b))
}
type Point struct {
X FieldElement
Y FieldElement
A FieldElement
B FieldElement
}
Now upon Point creation I want to check if a point is on the curve defined as y^2 = x^3 + ax + b
Each operation of FieldElement returns 2 values to satisfy the error checking.
So I can not do
x.Pow(3).Add(a.Mul(x)).Add(b)
and end up with
pow3, e1 := x.Pow(three)
mul, e2 := a.Mul(x)
add, e3 := pow3.Add(mul)
rval, e4 := add.Add(b)
// check that y^2 == rval
This makes the code hard to follow, what is the golang way to properly do this?
playground
Make your methods return only a single value, so they can be chained, and store the error value in that returned value, to check after. Example:
type FieldElement struct {
Num int
Prime int
Error error
}
func (el *FieldElement) Add(o FieldElement) *FieldElement {
if el.Error != nil {
// An error already happened, so do nothing
return el
}
if el.Prime != o.Prime {
el.Error = errors.New("cannot operate on two numbers in different Fields")
} else {
el.Num = (el.Num + o.Num) & el.Prime
}
return el
}
Then use it like this:
x.Add(...).Mul(...).Sub(...) // etc
if x.Error != nil {
// handle error here
}

function that accepts all numeric types (int, float, ..) and adds them

I would like to write a function that accepts two arguments of type int, int8, int16, ..., float, and float64. The type of arguments doesn't have to match. This function should take two arguments and add them. What is a good way to do this?
Essentially I want something like this:
func f(a interface{}, b interface{}) interface{} {
return a + b
}
f(int8(1), int16(2)) // 3
f(float64(2.2), int(1)) // 3.2
Is there a way to do this in Go? I'm open to using reflection, but would also like to see ways without reflection if possible.
To expand on #YandryPozo's answer, you can generate the combinations once, then you don't need to rely on formatting and parsing strings, or reflection. This will convert any numeric type to int64 or float64 to be added, returning one of those types. You could go through the individual cases and remove extra type conversions to only convert to the minimum common base which would be even more efficient, but then any type could be returned and you would have to type-switch all possible types on the return. You could even add string cases in there if you wanted to parse strings.
https://play.golang.org/p/e_4IMlsSR0 (or expanded out https://play.golang.org/p/M2niXz2It_)
func add(x, y interface{}) interface{} {
switch x := get64(x).(type) {
case int64:
switch y := get64(y).(type) {
case int64:
return x + y
case float64:
return float64(x) + y
}
case float64:
switch y := get64(y).(type) {
case int64:
return x + float64(y)
case float64:
return x + y
}
}
panic("invlaid input")
}
func get64(x interface{}) interface{} {
switch x := x.(type) {
case uint8:
return int64(x)
case int8:
return int64(x)
case uint16:
return int64(x)
case int16:
return int64(x)
case uint32:
return int64(x)
case int32:
return int64(x)
case uint64:
return int64(x)
case int64:
return int64(x)
case int:
return int64(x)
case float32:
return float64(x)
case float64:
return float64(x)
}
panic("invalid input")
}
If you want arbitrary precision for any arguments, without overflow or truncations, you could convert all arguments to math/big types. This example converts everything to a big.Float with a single type switch, and you could expand this like above to combine big.Int and big.Float.
func addBig(nums ...interface{}) *big.Float {
var total big.Float
for _, n := range nums {
total.Add(&total, getFloat(n))
}
return &total
}
func getFloat(i interface{}) *big.Float {
var f big.Float
switch i := i.(type) {
case uint8:
f.SetInt64(int64(i))
case int8:
f.SetInt64(int64(i))
case uint32:
f.SetInt64(int64(i))
case int32:
f.SetInt64(int64(i))
case uint64:
f.SetUint64(i)
case int64:
f.SetInt64(i)
case int:
f.SetInt64(int64(i))
case float32:
f.SetFloat64(float64(i))
case float64:
f.SetFloat64(float64(i))
}
return &f
}
Don't use reflection: Reflection is never clear
You have two good options, you can use switch with .(type) or doing an explicit cast to your desire type like a.(int), something like this:
func f1(a interface{}, b interface{}) interface{} {
switch ta := a.(type) {
case int:
switch b.(type) {
case int:
return a.(int) + b.(int)
}
case float64:
switch b.(type) {
case float64:
return a.(float64) + b.(float64)
}
// you can add all your combinations ... byte, uint, int64, float32 etc. etc.
default:
fmt.Printf("unrecognized type '%T'\n", ta)
}
return nil // like super zero value of interface{}
}
func f2(a interface{}, b interface{}) interface{} {
val_a, isAInt := a.(int)
if !isAInt {
return nil // a is not integer
}
val_b, isBInt := b.(int)
if !isBInt {
return nil // a is not integer
}
// more cast with different types (uint, floats, etc.)
return val_a + val_b
}
Full example: https://play.golang.org/p/RCeJikC8py
Adds any number of numeric arguments and even strings
func f(things... interface{}) interface{} {
var x, y big.Float
for _, v := range things {
if _, _, err := x.Parse(fmt.Sprint(v), 10); err != nil {
return nil
}
y.Add(&y, &x)
}
return y.String()
}
Playground: https://play.golang.org/p/HqCsy0UaDy

Is it possible to define a variable which type is depends on input in Golang

Learning Go and try to write an App which take bit depth as input, when bitDepth == 8, define a varable as var y []byte, When bitDepth == 10, define a variable var y []uint16
What's the right way to do it in Go?
Because there are no generics in go, you will still have to do type assertions if you use an empty interface i.e. interface{}.
The best option is to define an interface that provides all of the functionality you need, and implement it for all the datatypes you need to wrap.
package main
type SliceWrapper interface {
Slice(start, end int) SliceWrapper
Index(index int) int
}
func NewSlice(bitDepth int) SliceWrapper {
switch bitDepth {
case 8:
return make(Uint8Wrapper)
case 16:
return make(Uint16Wrapper)
}
}
type Uint8Wrapper []uint8
func (u Uint8Wrapper) Slice(s, e int) SliceWrapper {
return u[s:e]
}
func (u Uint8Wrapper) Index(i int) int {
return u[i]
}
type Uint16Wrapper []uint16
func (u Uint16Wrapper) Slice(s, e int) SliceWrapper {
return u[s:e]
}
func (u Uint16Wrapper) Index(i int) int {
return u[i]
}
You will need more functionality than that I am sure, but it is way cleaner than throwing interface{} around everywhere.
one way is:
package main
import (
"fmt"
)
func virtualVar(bitDepth int) interface{} {
var v interface{}
switch bitDepth {
case 8:
y := []byte{1, 2}
v = y
case 16:
y := []uint16{12345, 11000}
v = y
}
return v
}
func main() {
a := virtualVar(8)
b := virtualVar(16)
fmt.Println(a) //[1 2]
fmt.Println(b) //[12345 11000]
}

Convert interface{} to int

I'm trying to get a value from a JSON and cast it to int but it doesn't work, and I don't know how to do it properly.
Here is the error message:
...cannot convert val (type interface {}) to type int: need type assertion
And the code:
var f interface{}
err = json.Unmarshal([]byte(jsonStr), &f)
if err != nil {
utility.CreateErrorResponse(w, "Error: failed to parse JSON data.")
return
}
m := f.(map[string]interface{})
val, ok := m["area_id"]
if !ok {
utility.CreateErrorResponse(w, "Error: Area ID is missing from submitted data.")
return
}
fmt.Fprintf(w, "Type = %v", val) // <--- Type = float64
iAreaId := int(val) // <--- Error on this line.
testName := "Area_" + iAreaId // not reaching here
Instead of
iAreaId := int(val)
you want a type assertion:
iAreaId := val.(int)
iAreaId, ok := val.(int) // Alt. non panicking version
The reason why you cannot convert an interface typed value are these rules in the referenced specs parts:
Conversions are expressions of the form T(x) where T is a type and x is an expression that can be converted to type T.
...
A non-constant value x can be converted to type T in any of these cases:
x is assignable to T.
x's type and T have identical underlying types.
x's type and T are unnamed pointer types and their pointer base types have identical underlying types.
x's type and T are both integer or floating point types.
x's type and T are both complex types.
x is an integer or a slice of bytes or runes and T is a string type.
x is a string and T is a slice of bytes or runes.
But
iAreaId := int(val)
is not any of the cases 1.-7.
I am assuming: If you sent the JSON value through browser then any number you sent that will be the type float64 so you cant get the value directly int in golang.
So do the conversion like:
//As that says:
fmt.Fprintf(w, "Type = %v", val) // <--- Type = float64
var iAreaId int = int(val.(float64))
This way you can get exact value what you wanted.
Adding another answer that uses switch... There are more comprehensive examples out there, but this will give you the idea.
In example, t becomes the specified data type within each case scope. Note, you have to provide a case for only one type at a type, otherwise t remains an interface.
package main
import "fmt"
func main() {
var val interface{} // your starting value
val = 4
var i int // your final value
switch t := val.(type) {
case int:
fmt.Printf("%d == %T\n", t, t)
i = t
case int8:
fmt.Printf("%d == %T\n", t, t)
i = int(t) // standardizes across systems
case int16:
fmt.Printf("%d == %T\n", t, t)
i = int(t) // standardizes across systems
case int32:
fmt.Printf("%d == %T\n", t, t)
i = int(t) // standardizes across systems
case int64:
fmt.Printf("%d == %T\n", t, t)
i = int(t) // standardizes across systems
case bool:
fmt.Printf("%t == %T\n", t, t)
// // not covertible unless...
// if t {
// i = 1
// } else {
// i = 0
// }
case float32:
fmt.Printf("%g == %T\n", t, t)
i = int(t) // standardizes across systems
case float64:
fmt.Printf("%f == %T\n", t, t)
i = int(t) // standardizes across systems
case uint8:
fmt.Printf("%d == %T\n", t, t)
i = int(t) // standardizes across systems
case uint16:
fmt.Printf("%d == %T\n", t, t)
i = int(t) // standardizes across systems
case uint32:
fmt.Printf("%d == %T\n", t, t)
i = int(t) // standardizes across systems
case uint64:
fmt.Printf("%d == %T\n", t, t)
i = int(t) // standardizes across systems
case string:
fmt.Printf("%s == %T\n", t, t)
// gets a little messy...
default:
// what is it then?
fmt.Printf("%v == %T\n", t, t)
}
fmt.Printf("i == %d\n", i)
}
I whole-heartedly agree with zzzz's type assertion answer and I strongly prefer that way over others. That said, here's what I've had to do when the preferred method has not worked... (long story related to cross-serialization of data). You can even chain this into a switch statement with case errInt == nil and similar expressions.
package main
import "fmt"
import "strconv"
func main() {
var v interface{}
v = "4"
i, errInt := strconv.ParseInt(v.(string), 10, 64)
if errInt == nil {
fmt.Printf("%d is a int", i)
/* do what you wish with "i" here */
}
}
Like I said above, try type assertion first before trying this way.
maybe you need
func TransToString(data interface{}) (res string) {
switch v := data.(type) {
case float64:
res = strconv.FormatFloat(data.(float64), 'f', 6, 64)
case float32:
res = strconv.FormatFloat(float64(data.(float32)), 'f', 6, 32)
case int:
res = strconv.FormatInt(int64(data.(int)), 10)
case int64:
res = strconv.FormatInt(data.(int64), 10)
case uint:
res = strconv.FormatUint(uint64(data.(uint)), 10)
case uint64:
res = strconv.FormatUint(data.(uint64), 10)
case uint32:
res = strconv.FormatUint(uint64(data.(uint32)), 10)
case json.Number:
res = data.(json.Number).String()
case string:
res = data.(string)
case []byte:
res = string(v)
default:
res = ""
}
return
}
You can use reflect to help you determine the type and then convert.
func i2num(a interface{}) (interface{}, error) { // interface to number
aValue := reflect.ValueOf(a)
switch aValue.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return aValue.Int(), nil
case reflect.Float32, reflect.Float64:
return aValue.Float(), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return aValue.Uint(), nil
case reflect.Bool:
if a == true {
return 1, nil
}
return 0, nil
case reflect.String:
return strconv.ParseFloat(aValue.String(), 64)
default:
return nil, errors.New("type error")
}
}
To better understand the type conversion, look at the code below:
package main
import "fmt"
func foo(a interface{}) {
fmt.Println(a.(int)) // conversion of interface into int
}
func main() {
var a int = 10
foo(a)
}
This code executes perfectly and converts interface type to int type
For an expression x of interface type and a type T, the primary expression
x.(T) asserts that x is not nil and that the value stored in x is of type T. The notation x.(T) is called a type assertion.
More precisely, if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T. In this case, T must implement the (interface) type of x; otherwise the type assertion is invalid since it is not possible for x to store a value of type T. If T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T.
Going back to your code, this
iAreaId := val.(int)
should work good. If you want to check error occured while conversion, you can also re-write above line as
iAreaId, ok := val.(int)
I wrote a library that can help with type convertions
https://github.com/KromDaniel/jonson
js := jonson.New([]interface{}{55.6, 70.8, 10.4, 1, "48", "-90"})
js.SliceMap(func(jsn *jonson.JSON, index int) *jonson.JSON {
jsn.MutateToInt()
return jsn
}).SliceMap(func(jsn *jonson.JSON, index int) *jonson.JSON {
if jsn.GetUnsafeInt() > 50{
jsn.MutateToString()
}
return jsn
}) // ["55","70",10,1,48,-90]
Simplest way I did this. Not the best way but simplest way I know how.
import "fmt"
func main() {
fmt.Print(addTwoNumbers(5, 6))
}
func addTwoNumbers(val1 interface{}, val2 interface{}) int {
op1, _ := val1.(int)
op2, _ := val2.(int)
return op1 + op2
}
You need to do type assertion for converting your interface{} to int value.
iAreaId := val.(int)
iAreaId, ok := val.(int)
More information is available.
use cast.ToInt(anyValue)
I needed that, because the nasty endpoint which I need to use has a bug and sometimes is returning an integer as a string, sometimes as float64
https://github.com/spf13/cast
Best avoid casting by declaring f to be f the correct type to correspond to the JSON.

Resources