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

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)
}
}
}

Related

Is it possible to infer type parameters from what return values are assigned to?

Suppose I wrote two functions like this:
func ToInterfaceSlice[T any](s []T) []interface{} {
res := make([]interface{}, len(s))
for i, v := range s {
res[i] = v
}
return res
}
func FromInterfaceSlice[T any](s []interface{}) (res []T, err error) {
res = make([]T, len(s))
for i, v := range s {
vt, ok := v.(T)
if !ok {
return nil, fmt.Errorf("%v (type=%T) doesn't fit the target type %T", v, v, res)
}
res[i] = vt
}
return
}
When I parse type from the input parameters, I can simply use
var m = []int{1, 2, 3}
fmt.Println(ToInterfaceSlice(m))
The compiler knows the T is int.
However when I try passing type from the return variables
var m []int
m, _ = FromInterfaceSlice([]interface{}{1, 2, 3})
fmt.Println(m)
The compiler gives error:
.\scratch.go:29:27: cannot infer T
I must explicitly pass the type in the function call:
var m []int
m, _ = FromInterfaceSlice[int]([]interface{}{1, 2, 3})
fmt.Println(m)
Is there anything hard to infer type parameters from return type when the receiver vars are not interface? Or just not implemented, even not to implement on purpose?
Update #1 after the comment
I do know a, b := GenericFunc() cannot refer the type of returned value. Currently Go does have "it depends" case whether requires the explicit instantiation or not from the user input.
type Set[T comparable] map[T]struct{}
func NewSet[T comparable](eles ...T) Set[T] {
s := make(Set[T])
for _, ele := range eles {
s[ele] = struct{}{}
}
return s
}
It's okay to use both t := NewSet(1, 2, 3) and t := NewSet[string](), but not var t NewSet[float64] = NewSet() now because of this
The current rules for type inference are explicit. How the return values are used is not taken into account:
Type inference is based on
a type parameter list
a substitution map M initialized with the known type arguments, if any
a (possibly empty) list of ordinary function arguments (in case of a function call only)
As of Go 1.18 might simply rewrite your function to accept an argument of the required type; this has also the benefit of not hiding allocations inside the function body:
func FromInterfaceSlice[T any](s []interface{}, dst []T) error {
if len(s) != len(dst) {
return errors.New("lengths don't match")
}
for i, v := range s {
vt, ok := v.(T)
if !ok {
return nil, fmt.Errorf("%v (type=%T) doesn't fit the target type %T", v, v, res)
}
dst[i] = vt
}
return nil
}
And pass in a destination slice with the required length:
func main() {
src := []interface{}{1, 2, 3}
m := make([]int, len(src))
_ = FromInterfaceSlice(src, m)
fmt.Println(m)
}
If you can't or don't want to determine the slice's length beforehand, you are left with explicit instantiation:
var m []int
m, _ = FromInterfaceSlice[int]([]interface{}{1, 2, 3})
// ^^^ explicit type argument
Also the type parameters are still not inferrable with := shorthand declaration:
// what is m???
m, err := FromInterfaceSlice([]interface{}{1, 2, 3})

How to determine the element type of slice interface{}?

I have the following code to double the slice.
func doubleSlice(s []int) []int {
t := make([]int, len(s), (cap(s) + 1) * 2 )
for i := range s {
t[i] = s[i]
}
return t
}
I want to make the func to double any type of slice. And I need to know the element type first.
func showInterfaceItem(s interface{}) interface{} {
if reflect.TypeOf(s).Kind() != reflect.Slice {
fmt.Println("The interface is not a slice.")
return
}
var t interface{}
newLen := reflect.ValueOf(s).Len()
newCap := (cap(reflect.ValueOf(s).Cap()) + 1) * 2
t = make([]reflect.TypeOf(s), newLen, newCap)
return t
}
The reflect.TypeOf(s) return the type of interface{}, not the type of element. How can I get the element type of slice interface?
You can use reflect.TypeOf(s).Elem()
to get the type of element of slice.
package main
import (
"fmt"
"reflect"
)
func doubleSlice(s interface{}) interface{} {
if reflect.TypeOf(s).Kind() != reflect.Slice {
fmt.Println("The interface is not a slice.")
return nil
}
v := reflect.ValueOf(s)
newLen := v.Len()
newCap := (v.Cap() + 1) * 2
typ := reflect.TypeOf(s).Elem()
t := reflect.MakeSlice(reflect.SliceOf(typ), newLen, newCap)
reflect.Copy(t, v)
return t.Interface()
}
func main() {
xs := doubleSlice([]string{"foo", "bar"}).([]string)
fmt.Println("data =", xs, "len =", len(xs), "cap =", cap(xs))
ys := doubleSlice([]int{3, 1, 4}).([]int)
fmt.Println("data =", ys, "len =", len(ys), "cap =", cap(ys))
}
The output will be:
data = [foo bar] len = 2 cap = 6
data = [3 1 4] len = 3 cap = 8
Check it in: Go Playground
This is doable in golang and takes me whole day to discover the pattern.
Firstly, we want to get a pointer of slice to make gorm happy, which is has type "*[]Obj". To achieve that in golang, we can create a make wrapper like so:
func makeWrapper(cap uint) interface{} {
arr:= make([]Sth, 0, cap)
return &arr
}
Notice that, we can't directly reference the maked value, which might be the book keeping data need to have a stack space to store.
//Not working example
func makeWrapper(cap uint) interface{} {
return &(make([]Sth, 0, cap))
}
And as the answer before, the reflect.MakeSlice(reflect.SliceOf(typ), 0, capacity).Interface() returns interface{[]Sth}. (the typ here is refer to reflect.TypeOf(Sth{}), which equiv to typ == reflect.TypeOf(v))
Thus we need to create a return object of *[]Sth and the value inside is a slice []Sth with capacity. After understanding the objective, we can have this code:
package main
import (
"reflect"
)
type Sth struct {
a, b string
}
func main() {
af:= createSlice(Sth{})
arr := makeWrapper(10).(*[]Sth)
println(reflect.TypeOf(arr).String())
// equiv to makeWrapper, but we do it via reflection
arr = af(10).(*[]Sth)
println(reflect.TypeOf(arr).String())
}
func makeWrapper(cap uint) interface{} {
arr:= make([]Sth, 0, cap)
return &arr
}
func createSlice(v interface{}) func(int) interface{} {
var typ reflect.Type
if reflect.ValueOf(v).Kind() == reflect.Ptr {
typ = reflect.ValueOf(v).Elem().Type()
} else if reflect.ValueOf(v).Kind() == reflect.Struct {
typ = reflect.TypeOf(v)
} else {
panic("only support instance of struct or pointer of that instance")
}
return func(capacity int) interface{}{
// create the outer object saves our slice
outerObj:=reflect.New(reflect.SliceOf(typ))
// create the slice and save it to return
outerObj.Elem().Set(reflect.MakeSlice(reflect.SliceOf(typ), 0, capacity))
// retrive the interface of outer object
return outerObj.Interface()
}
}

Short way to apply a function to all elements in a list in golang

Suppose I would like to apply a function to every element in a list, and then put the resulting values in another list so I can immediately use them. In python, I would do something like this:
list = [1,2,3]
str = ', '.join(multiply(x, 2) for x in list)
In Go, I do something like this:
list := []int{1,2,3}
list2 := []int
for _,x := range list {
list2 := append(list2, multiply(x, 2))
}
str := strings.Join(list2, ", ")
Is it possible to do this in a shorter way?
I would do exactly as you did, with a few tweaks to fix typos
import (
"fmt"
"strconv"
"strings"
)
func main() {
list := []int{1,2,3}
var list2 []string
for _, x := range list {
list2 = append(list2, strconv.Itoa(x * 2)) // note the = instead of :=
}
str := strings.Join(list2, ", ")
fmt.Println(str)
}
This is an old question, but was the top hit in my Google search, and I found information that I believe will be helpful to the OP and anyone else who arrives here, looking for the same thing.
There is a shorter way, although you have to write the map function yourself.
In go, func is a type, which allows you to write a function that accepts as input the subject slice and a function, and which iterates over that slice, applying that function.
See the Map function near the bottom of this Go by Example page : https://gobyexample.com/collection-functions
I've included it here for reference:
func Map(vs []string, f func(string) string) []string {
vsm := make([]string, len(vs))
for i, v := range vs {
vsm[i] = f(v)
}
return vsm
}
You then call it like so:
fmt.Println(Map(strs, strings.ToUpper))
So, yes: The shorter way you are looking for exists, although it is not built into the language itself.
I've created a small utility package with Mapand Filter methods now that generics have been introduced in 1.18 :)
https://pkg.go.dev/github.com/sa-/slicefunk
Example usage
package main
import (
"fmt"
sf "github.com/sa-/slicefunk"
)
func main() {
original := []int{1, 2, 3, 4, 5}
newArray := sf.Map(original, func(item int) int { return item + 1 })
newArray = sf.Map(newArray, func(item int) int { return item * 3 })
newArray = sf.Filter(newArray, func(item int) bool { return item%2 == 0 })
fmt.Println(newArray)
}
With go1.18+ you can write a much cleaner generic Map function:
func Map[T, V any](ts []T, fn func(T) V) []V {
result := make([]V, len(ts))
for i, t := range ts {
result[i] = fn(t)
}
return result
}
Usage, e.g:
input := []int{4, 5, 3}
outputInts := Map(input, func(item int) int { return item + 1 })
outputStrings := Map(input, func(item int) string { return fmt.Sprintf("Item:%d", item) })
Found a way to define a generic map array function
func Map(t interface{}, f func(interface{}) interface{} ) []interface{} {
switch reflect.TypeOf(t).Kind() {
case reflect.Slice:
s := reflect.ValueOf(t)
arr := make([]interface{}, s.Len())
for i := 0; i < s.Len(); i++ {
arr[i] = f(s.Index(i).Interface())
}
return arr
}
return nil
}
origin := []int{4,5,3}
newArray := Map(origin, func(item interface{}) interface{} { return item.(int) + 1})
You can use lo's Map in order to quickly apply a function to all elements. For example, in order to multiply by 2 and convert to string, you can use:
l := lo.Map[int, string]([]int{1, 2, 3, 4}, func(x int, _ int) string { return strconv.Itoa(x * 2) })
Then you can convert back to a comma delimited string like so:
strings.Join(l, ",")

Idiomatic way of implementing nested matrices in golang

I am trying to represent a hypergraph in memory. Are there any better data structures for this task beside nested matrices? A nested matrix is a matrix which can have elements of both the "native" type (let's say int for the sake of simplicity) and matrices.
This is the beginning of such a matrix. Are there any rough edges in the code, to make it look more idiomatic? How to make it look more idiomatic?
The code:
package main
import "fmt"
type Matricial interface {
Put(interface{}, ...int)
Get(...int) interface{}
}
type Matrix struct {
Matricial
values map[int]interface{}
}
func NewMatrix() *Matrix {
m := &Matrix{}
m.values = make(map[int]interface{})
return m
}
func (m *Matrix) Set(atom interface{}, pos ...int) {
firstdim := pos[0]
if val, ok := m.values[firstdim]; ok {
fmt.Println("map key exists", val)
switch converted := val.(type) {
case int:
m.values[firstdim] = converted
default:
fmt.Println("ERR: unknown type: %T", val)
}
} else {
if len(pos[1:]) > 0 {
newm := NewMatrix()
m.values[firstdim] = newm
newm.Set(atom, pos[1:]...)
} else {
m.values[firstdim] = atom
}
}
}
func (m *Matrix) Get(pos ...int) interface{} {
if len(pos) == 1 {
return m.values[pos[0]]
} else {
switch accessor := m.values[pos[0]].(type) {
case Matricial:
return accessor.Get(pos[1:]...)
default:
return nil
}
}
return nil
}
func main() {
m := NewMatrix()
m.Set(42, 2, 3, 4)
m.Set(43, 0)
fmt.Println(m.Get(2, 3))
fmt.Println(m.Get(2, 3, 4))
fmt.Println(m.Get(0))
}
The data structure must allow connecting hyperedges with other hyperedges (i.e. handling hyperedges as though they were nodes).
A nested matrix (adopting your definition of the term) seems a reasonable representation for hypergraph, not knowing anything more about your application anyway. An example Go implementation is the power set example at Rosetta code.
It is not idiomatic to embed an interface. For example, if you rename the Put method of Matricial to be Set, which is what I think you meant, then you can just delete the Matricial field of Matrix and your program produces the same output.

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