Helper func to assign respective data to its key - go

So I have this data struct:
type Parent struct {
A ChildA
B ChildB
C ChildC
D ChildD
}
type ChildA struct {
...
}
I am trying to create a helper funct such that I can reduce my LOC when it comes to variable assignment.
What I am trying to do:
func SomeHelper( SomeChild Child? ) Parent {
return Parent{
?: SomeChild
}
}
"?" can be any of the key A B C D

We can use variadic function and reflection.
this is the example code:
package main
import (
"errors"
"fmt"
"reflect"
)
type Parent struct {
A ChildA
B ChildB
C ChildC
D ChildD
}
type ChildA struct {
x string
}
type ChildB struct {
x string
}
type ChildC struct {
}
type ChildD struct {
}
func helper(childs ...any) (Parent, error) {
check := make(map[string]int)
var p Parent
for _, v := range childs {
if v == nil {
continue
}
childType := reflect.TypeOf(v)
check[childType.String()]++
if check[childType.String()] > 1 {
return p, errors.New("child must be unique")
}
switch childType.String() {
case "main.ChildA":
p.A = v.(ChildA)
case "main.ChildB":
p.B = v.(ChildB)
case "main.ChildC":
p.C = v.(ChildC)
case "main.ChildD":
p.D = v.(ChildD)
}
}
return p, nil
}
func main() {
p, err := helper(ChildA{"hello"}, ChildB{"world"}, ChildC{})
if err != nil {
panic(err)
}
fmt.Println(p)
}

You can use Visitor pattern.
type Parent struct {
A ChildA
B ChildB
C ChildC
}
type Child interface {
VisitParent(*Parent)
}
type ChildA struct{}
func (c ChildA) VisitParent(parent *Parent) {
parent.A = c
}
type ChildB struct{}
func (c ChildB) VisitParent(parent *Parent) {
parent.B = c
}
type ChildC struct{}
func (c ChildC) VisitParent(parent *Parent) {
parent.C = c
}
func SomeHelper(someChild Child) Parent {
parent := Parent{}
someChild.VisitParent(&parent)
return parent
}

Related

how can i get child struct name in parent func?

how can i get child struct name in parent func? my online code is here:
https://go.dev/play/p/04w5mK0aAgL
type IParent interface {
TypeName() string
}
type Parent struct{ IParent }
func (p *Parent) TypeName() string {
if t := reflect.TypeOf(p); t.Kind() == reflect.Ptr {
return "*" + t.Elem().Name()
} else {
return t.Name()
}
}
type Child struct {
*Parent
}
func main() {
var e IParent = &Child{}
// output: TypeName: *Parent.
// expected: TypeName: *Child.
val := e.TypeName()
fmt.Printf("TypeName: %v.\n", val)
}
the output is TypeName: *Parent., my expected output is TypeName: *Child., could someone can give me some suggest?
I think u miss with the concept of struct in go.
type Child struct {
*Parent
}
func main() {
var e IParent = &Child{}
Above, clearly if u define the struct Child with Parent as the content of struct, but afterthat u declare the child and output the content. In here so clearly the result is *Parent.

How can Subtype be referenced by Supertype in Go

Go doesn't support Polymorphism.If specific types were to be passed under the umbrella of Generic types it fails to work in Go. Following piece of code throws error . What is the best way to achieve the same functionality in Go?
package main
import (
"fmt"
)
type parent struct {
parentID string
}
type child1 struct {
parent
child1ID string
}
type child2 struct {
parent
child2ID string
}
type childCollection struct {
collection []parent
}
func (c *childCollection) appendChild(p parent) {
c.collection = append(c.collection, p)
}
func main() {
c1 := new(child1)
c2 := new(child2)
c := new(childCollection)
c.appendChild(c1)
c.appendChild(c2)
}
Go Playground Link
Just because the type Child is composed of something Parent in this case. does not mean that it is that something. These are two different types so cannot be interchangeable in this way.
Now if you had an interface Parent and your child objects meet that interface then we are talking a different thing altogether.
Edit 1
Example
https://play.golang.org/p/i6fQBoL2Uk7
Edit 2
package main
import "fmt"
type parent interface {
getParentId() (string)
}
type child1 struct {
child1ID string
}
func (c child1) getParentId() (string) {
return c.child1ID
}
type child2 struct {
child2ID string
}
func (c child2) getParentId() (string) {
return c.child2ID
}
type childCollection struct {
collection []parent
}
func (c *childCollection) appendChild(p parent) {
c.collection = append(c.collection, p)
}
func main() {
c1 := child1{"1"}
c2 := child2{"2"}
c := new(childCollection)
c.appendChild(c1)
c.appendChild(c2)
fmt.Println(c)
}

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

How to get embedded type from GO struct?

I am trying to get embedded type from Go structs. Below is an example program that demonstrates this. Is there a way to write myfunc() without enumerating every type that can come in as input?
https://play.golang.org/p/5wp14O660m
package main
import (
"fmt"
)
type ObjectMeta struct {
Name string
Namespace string
}
type A struct {
ObjectMeta
X string
}
type B struct {
ObjectMeta
X string
}
func myfunc(v interface{}) ObjectMeta {
switch u := v.(type) {
case *A:
return u.ObjectMeta
case A:
return u.ObjectMeta
case *B:
return u.ObjectMeta
case B:
return u.ObjectMeta
}
panic("No matching type")
}
func main() {
fmt.Println(myfunc(&A{}))
var v interface{} = &A{}
fmt.Println(v.(*ObjectMeta))
}
ObjectMeta, A, B structs exist in external project. I have no control over them.
It can be done using reflection, iterating through the fields of the incoming value:
func myfunc(v interface{}) ObjectMeta {
// Elem() to de-reference pointer
ifv := reflect.ValueOf(v).Elem()
ift := reflect.TypeOf(v).Elem()
for i := 0; i < ift.NumField(); i++ {
f := ift.Field(i)
if f.Name == "ObjectMeta" {
fv := ifv.Field(i)
return fv.Interface().(ObjectMeta)
}
}
panic("ObjectMeta not found")
}
Playground: https://play.golang.org/p/CzMHJWhxYr
You can define interface which will get you that embedded type:
package main
import (
"fmt"
)
type HasMeta interface {
GetMeta() ObjectMeta
}
type ObjectMeta struct {
Name string
Namespace string
}
func (o ObjectMeta) GetMeta() ObjectMeta {
return o
}
type A struct {
ObjectMeta
X string
}
type B struct {
ObjectMeta
X string
}
func myfunc(o HasMeta) ObjectMeta {
return o.GetMeta()
}
func main() {
fmt.Println(myfunc(&A{}))
fmt.Println(myfunc(A{}))
fmt.Println(myfunc(&B{}))
fmt.Println(myfunc(B{}))
}
https://play.golang.org/p/CWa4k-kvvl

How can I compare struct data and interface data in Golang?

I am trying to create a generic Binary Tree in Golang. How can I compare data from an interface and input data in the code? Here is an example of what I am trying to do. The comparison that is giving me trouble is this
} else if cur.data < data {
-
package DSAA
type TreeNode struct {
data interface{}
right *TreeNode
left *TreeNode
}
type BinarySearchTree struct {
root *TreeNode
}
func BSTCreate() *BinarySearchTree {
return &BinarySearchTree{nil}
}
func (b *BinarySearchTree) Insert(cur TreeNode, data interface{}) *BinarySearchTree {
if &cur == nil {
cur := &TreeNode{data, nil, nil}
} else if cur.data < data {
b = b.Insert(*cur.left, data)
} else {
b = b.Insert(*cur.right, data)
}
return b
}
You have some options:
1- Using runtime type switch:
package main
import (
"fmt"
)
func main() {
fmt.Println(Less(1, 2)) // true
fmt.Println(Less("AB", "AC")) // true
}
func Less(a, b interface{}) bool {
switch v := a.(type) {
case int:
w := b.(int)
return v < w
case string:
w := b.(string)
return v < w
}
return false
}
then replace } else if cur.data < data { with
} else if Less(cur.data , data) {
2- Using Comparer interface:
package main
import (
"fmt"
)
type Comparer interface {
// Less reports whether the element is less than b
Less(b interface{}) bool
}
func main() {
a, b := Int(1), Int(2)
fmt.Println(a.Less(b)) // true
c, d := St("A"), St("B")
fmt.Println(c.Less(d)) // true
}
type Int int
func (t Int) Less(b interface{}) bool {
if v, ok := b.(Int); ok {
return int(t) < int(v)
}
return false
}
type St string
func (t St) Less(b interface{}) bool {
if v, ok := b.(St); ok {
return string(t) < string(v)
}
return false
}
3- Using reflect

Resources