Iterate through all the methods using range for loop - go

I have a struct with methods defined in it, i want to iterate through all the methods. Can i use interface {} or any other way to achieve this ?
type SomeStruct struct {
m_boolVals []bool
m_stringVals []string
m_intVals []int64
}
func (m *SomeStruct) GetBool() []bool {
return m.m_boolVals
}
func (m *SomeStruct) GetString() []string {
return m_stringVals
}
func (m *SomeStruct) GetInts() []int64 {
return m_intVals
}
Is there a way to achieve below code ? So basically only one of value would be present
fun SomeOtherFunc(ss *SomeStruct) []string {
var final_string []string
for _, handlerFunc := range(ss.GetBool, ss.GetString, ss.GetInts) {
generic_vals := handlerFunc()
if (len(generic_vals) > 0) {
for _, t_val := range(generic_vals) {
final_string = append(final_string , string(t_val))
}
break
}
}
return final_string
}

Here's an example how you can use reflection to iterate over the methods and call each, and convert their result to string:
func SomeOtherFunc(ss *SomeStruct) []string {
var result []string
v := reflect.ValueOf(ss)
for i := 0; i < v.NumMethod(); i++ {
for _, res := range v.Method(i).Call(nil) {
result = append(result, fmt.Sprint(res.Interface()))
}
}
return result
}
Testing it:
fmt.Println(SomeOtherFunc(&SomeStruct{
m_boolVals: []bool{true, false},
m_stringVals: []string{"one", "two"},
m_intVals: []int64{1, 2, 3},
}))
Which outputs (try it on the Go Playground):
[[true false] [1 2 3] [one two]]

Related

How to convert a slice of int to a slice of string

Well, I created a slice of int like this:
list_of_id := []string {1,2,3,4}
My code would do a check if a variable in my slice (list_of_id):
func contains(s [] int, input int) bool {
for _, v := range s {
if v == input {
return true
}
}
return false
}
func main() {
list_of_id := [] int {1,2,3,4}
fmt.Println(contains(list_of_id, 1))
}
I want to create a function with the flexibility that I could input 1 or "1" as well.
My intention is to create an if else condition in which the slice of int [] int {1,2,3,4} will be converted into a slice of string [] string {"1","2","3","4"} to check again.
Anddddd, I don't know how to do so. I tried to google it out but all I found is a solution to convert this [] int {1,2,3,4} to this "{1,2,3,4}"
import "strconv"
func contains(s [] int, input interface{}) bool {
switch i := input.(type) {
case int:
for _, v := range s {
if v == i {
return true
}
}
case string:
for _, v := range s {
if strconv.Itoa(v) == i {
return true
}
}
}
return false
}
https://play.golang.org/p/02J1f77n_aM
package main
import (
"fmt"
"strconv"
)
func contains(s []int, input interface{}) bool {
var c int
var err error
switch input.(type) {
case int:
c = input.(int)
case string:
tmp := input.(string)
c, err = strconv.Atoi(tmp)
}
if err != nil {
return false
}
for _, v := range s {
if v == c {
return true
}
}
return false
}
func main() {
list_of_id := []int{1, 2, 3, 4}
fmt.Println(contains(list_of_id, 3))
fmt.Println(contains(list_of_id, 5))
fmt.Println(contains(list_of_id, "1"))
fmt.Println(contains(list_of_id, "6"))
}
Here example

Can a variable be used as a placeholder for a function call?

I am writing a program which has several structs and functions to handle these structs differently. I am having a generic function which calls the required function based on the inputs. Is there a generic way to use the returned value from getStruct()?
package main
var X func(s []string) A
var Y func(s []string) B
type A struct {
Name string
Place string
}
type B struct {
Name string
Place string
Value string
}
func newA(s []string) A {
a := A{
Name: s[0],
Place: s[1],
}
return a
}
func newB(s []string) B {
a := B{
Name: s[0],
Place: s[1],
Value: s[2],
}
return a
}
func getStruct(t string) interface{} {
switch {
case t == "A":
return X
case t == "B":
return Y
default:
return //someStruct
}
}
func main() {
buildNewStruct := getStruct("A") //Lets assume "A" here is got as an argument
var strSlice = []string{"Bob", "US"}
buildNewStruct(strSlice) //How to do this operation?
//I am hoping to use buildNewStruct(strSlice) to dynamically call
//either of newA(strSlice) or newB(strSlice) function
}
I have tried looking at this and this the later is not exactly the same as my question.
Since I am new to go, I am not sure if something like this is possible.
you can use the reflect package to set the struct properties to the equivalent index positioned value from an []interface{} slice.
package main
import (
"fmt"
"log"
"reflect"
)
func main() {
var a A
err := decode(&a, []interface{}{"Name", "Place"})
log.Println(err)
log.Println(a)
}
func decode(dst interface{}, values []interface{}) error {
rvptr := reflect.ValueOf(dst)
if rvptr.Kind() != reflect.Ptr {
return fmt.Errorf("value must be ptr")
}
rv := rvptr.Elem()
if rv.NumField() < len(values) {
return fmt.Errorf("too many values")
}
if rv.NumField() > len(values) {
return fmt.Errorf("too few values")
}
rvalues := reflect.ValueOf(values)
for i := range values {
f := rv.FieldByIndex([]int{i})
f.Set(rvalues.Index(i).Elem())
}
return nil
}
type A struct {
Name string
Place string
}
type B struct {
Name string
Place string
Value string
}
prints
$ go run main.go
2019/11/21 17:00:17 <nil>
2019/11/21 17:00:17 {Name Place}
The problem is the return type for the function.
func newA(in []string) interface{} {...}
func newB(in []string) interface{} {...}
func getStruct(name string) func([]string) interface{} {
switch name {
case "A": return newA
case "B": return newB
}
return nil
}
func main() {
buildNewStruct := getStruct("A")
var strSlice = []string{"Bob", "US"}
str:=buildNewStruct(strSlice)
if a, ok:=str.(A); ok {
...
}
}
With this approach, even though you saved some code by calling a unified buildNewStruct(), you have to use type assertions to figure out what is returned from that function, so this may not make a lot of sense. It depends on your exact use case though.

common function to create map[string]struct from slice of struct dynamically

I have two different struct as mentioned below A abd B and two process functions. Is there any way by means of which i can write a common function to generate the map[string]struct for the both the struct. Moreover, is there any way using reflection given the struct name i can create the object of the same?
type A struct {
name string
// more fields
}
type B struct {
name string
// more fields
}
func ProcessA(input []A) map[string]A {
output := make(map[string]A)
for _, v := range input {
output[v.name] = v
}
return output
}
func ProcessB(input []B) map[string]B {
output := make(map[string]B)
for _, v := range input {
output[v.name] = v
}
return output
}
Idiomatic way in Go would be to use interface.
type Named interface {
Name() string
}
type letter struct {
name string
}
func (l letter) Name() string {
return l.name
}
type A struct {
letter
// more fields
}
type B struct {
letter
// more fields
}
func ProcessNameds(input []Named) map[string]Named {
output := make(map[string]Named, len(input))
for _, v := range input {
output[v.Name()] = v
}
return output
}
Well, see if something like this would help:
package main
import (
"fmt"
"strconv"
)
type A struct {
name string
// more fields
}
type B struct {
name string
// more fields
}
func Process(x interface{}) interface{} {
ma := make(map[string]int)
mb := make(map[string]string)
if x == nil {
return nil
} else if a, ok := x.([]A); ok {
fmt.Printf("Type A argument passed %s\n", x)
ma[a[0].name] = 1
ma[a[1].name] = 2
return ma //you can return whatever type you want here
} else if b, ok := x.([]B); ok {
fmt.Printf("Type B argument passed %s\n", x)
mb[b[0].name] = "a"
mb[b[1].name] = "b"
return mb //you can return whatever type you want here
} else {
panic(fmt.Sprintf("Unexpected type %T: %v", x, x))
}
return nil
}
func main() {
a := make([]A, 5)
for i := 0; i < len(a); i++ {
a[i].name = strconv.Itoa(i) + "A"
}
b := make([]B, 7)
for i := 0; i < len(b); i++ {
b[i].name = strconv.Itoa(i) + "B"
}
fmt.Println(Process(a))
fmt.Println(Process(b))
//Uncomment line below to see the panic
//fmt.Println(Process(8))
}
https://play.golang.org/p/irdCsbpvUv_t

Golang convert list objects to string

I have two structs:
type A struct {
BankCode string `json:"bankCode"`
BankName string `json:"bankName"`
}
And:
type B struct {
A
extra string `json:" extra"`
}
And two slices:
listsA []A and listsB []B
I want to get bankCodes from listA and listB. bankcodes only contains bankcodes. It is a []string
It will be so easy as using two function.
func getBankCodes(data []A) []string {
res := make([]string, len(data))
for i := 0; i < len(data); i++ {
res[i] = data[i].BankCode
}
return res
}
func getBankCodes(data []B) []string {
res := make([]string, len(data))
for i := 0; i < len(data); i++ {
res[i] = data[i].BankCode
}
return res
}
How to use one common function ?
Well the clean solution would be to use an interface, since go doesn't support classic inheritance, so something like []parentclass can't work. Interfaces however can only describe functions not a common field, so you have to implement a Getter (essentially).
// GetBankCoder provides a function that gives the BankCode
type GetBankCoder interface {
getBankCode() string
}
// implement GetBankCoder for A (and indirectly for B)
func (a A) getBankCode() string {
return a.BankCode
}
and make your getBankCodes work on that interface type, notice the parameter of the function as well as the statement inside the loop:
func getBankCodes(data []GetBankCoder) []string { // <-- changed
res := make([]string, len(data))
for i := 0; i < len(data); i++ {
res[i] = data[i].getBankCode() // <-- changed
}
return res
}
There are other solutions where the function parameter is of interface{} type and then reflection is used to assure you can actually do .BankCode, but I don't like those, as they are not adding more clarity either.
... However, I couldn't get the golang playground to make this work correctly without putting it into a []GetBankCoder var first, before giving it to the function.
banks := make([]GetBankCoder, 0)
banks = append(banks, A{ BankCode: "ABC", BankName: "ABC Bank"})
getBankCodes(banks)
You may use one common function like so:
func BankCodes(data interface{}) []string {
if reflect.TypeOf(data).Kind() != reflect.Slice {
panic("err: data is not slice")
}
slice := reflect.Indirect(reflect.ValueOf(data))
res := make([]string, slice.Len())
for i := 0; i < slice.Len(); i++ {
a := slice.Index(i).Interface().(BankCoder)
res[i] = a.Bankcode()
}
return res
}
Code (try on The Go Playground):
package main
import (
"fmt"
"reflect"
)
func main() {
bs := []B{B{A{"BC1", "BN"}, "e"}, B{A{"BC2", "BN"}, "e"}}
strs := BankCodes(bs)
fmt.Println(strs)
as := []A{A{"AC1", "BN"}, A{"AC2", "BN"}}
strs2 := BankCodes(as)
fmt.Println(strs2)
}
func BankCodes(data interface{}) []string {
if reflect.TypeOf(data).Kind() != reflect.Slice {
panic("err: data is not slice")
}
slice := reflect.Indirect(reflect.ValueOf(data))
res := make([]string, slice.Len())
for i := 0; i < slice.Len(); i++ {
a := slice.Index(i).Interface().(BankCoder)
res[i] = a.Bankcode()
}
return res
}
type A struct {
BankCode string `json:"bankCode"`
BankName string `json:"bankName"`
}
type B struct {
A
extra string `json:" extra"`
}
type BankCoder interface {
Bankcode() string
}
func (a A) Bankcode() string {
return a.BankCode
}

In Go, how can I make a generic function with slices?

Let's say I want to write a function that finds a value in a slice
I intuitively want to write:
func find(s []interface{}, f func(interface{})bool) int {
for i, item := range s {
if f(item) {
return i
}
}
return -1
}
however I don't manage to do this with Go. I could have an interface with
Len() int
Value(int) interface{}
...
and this would work but in my real code things are more complicated (I need to do slices[from:end] etc), append, ... etc and if I redefine all this in an interface I end up having a lot of code. Is there a better way?
You can use reflection. I wrote this function for a project, feel free to use it:
// InSlice returns true if value is in slice
func InSlice(value, slice interface{}) bool {
switch reflect.TypeOf(slice).Kind() {
case reflect.Slice, reflect.Ptr:
values := reflect.Indirect(reflect.ValueOf(slice))
if values.Len() == 0 {
return false
}
val := reflect.Indirect(reflect.ValueOf(value))
if val.Kind() != values.Index(0).Kind() {
return false
}
for i := 0; i < values.Len(); i++ {
if reflect.DeepEqual(values.Index(i).Interface(), val.Interface()) {
return true
}
}
}
return false
}
if you have predefined type like []int or []string and do not want to convert to []interface{} see this working sample code (without using reflect):
package main
import "fmt"
func find(s []int, f func(int) bool) int {
for i, item := range s {
if f(item) {
return i
}
}
return -1
}
func findString(s []string, f func(string) bool) int {
for i, item := range s {
if f(item) {
return i
}
}
return -1
}
func main() {
s := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(find(s, func(a int) bool { return a == 5 })) //5
strs := []string{"A", "B", "C"}
fmt.Println(findString(strs, func(a string) bool { return a == "B" })) //1
}
or you may use reflect,like this working sample code:
package main
import "fmt"
import "reflect"
func find(slice interface{}, f func(interface{}) bool) int {
switch reflect.TypeOf(slice).Kind() {
case reflect.Slice:
values := reflect.Indirect(reflect.ValueOf(slice))
for i := 0; i < values.Len(); i++ {
if f(values.Index(i).Interface()) {
return i
}
}
}
return -1
}
func main() {
a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(find(a, func(i interface{}) bool { return i == 5 })) //5
b := []string{"A", "B", "C"}
fmt.Println(find(b, func(i interface{}) bool { return i == "B" })) //1
}
output:
5
1
I hope this helps.
I think, if you want to have slice of arbitrary values and use that sort of find function and have the possibility of standard [] reslicing, maybe the best way is to encapsulate your interface{} with another struct
type proxy struct {
val interface{}
}
and use
func find(s []proxy , f func(proxy)bool) int {}
and have the f function deal with interface{} comparison / type casting.

Resources