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.
Related
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
}
I am trying to append items to this struct I have:
type AuditSource struct {
Source map[string][]Pgm `json:"Source"`
}
type Pgm struct {
ID uint `json:"id,omitempty"`
SourceIP Inet `json:"sourceip,omitempty"`
MulticastPort int `json:"multicastport,omitempty"`
}
func NewAuditSource(lid string) (a *AuditSource) {
a = &AuditSource{
Id: make(map[string]uint64),
Source: make(map[string][]Pgm),
}
return
}
func (as *AuditSource) AuditSourceDifferences(a, b int) bool{
if a != b {
as.Source["Primary"][0].MulticastPort =a //ERRORS out every time
as.Source["Primary"][1].MulticastPort =b
}
return true
}
Any idea why my struct map[string][]Pgm errors out every time I try to add something to it? Do I need to initialize []Pgm perhaps?
There are some error in the code:
Inet type is not defined
AuditSource type does not contains Id used in NewAuditSource function
AuditSourceDifferences function does not contains the if statement
You are appending on a (probable) not existent value of the array using the index 0 and 1 in AuditSourceDifferences function
You have used the same name (a) to the input value (a, b int) and the struct receiver (a *AuditSource)
Try with the following code
package yourPackage
type AuditSource struct {
Source map[string][]Pgm `json:"Source"`
Id map[string]uint64
}
type Pgm struct {
ID uint `json:"id,omitempty"`
SourceIP Inet `json:"sourceip,omitempty"`
MulticastPort int `json:"multicastport,omitempty"`
}
func NewAuditSource(lid string) (a *AuditSource) {
a = &AuditSource{
Id: make(map[string]uint64),
Source: make(map[string][]Pgm),
}
return
}
func (a *AuditSource) AuditSourceDifferences(i, j int) bool {
if i != j {
a.Source["Primary"] = append(a.Source["Primary"], Pgm{MulticastPort: i},Pgm{MulticastPort: j})
}
return true
}
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)
}
I wonder how the following functions lengthAA and lengthBB can be simplified to just one function. Note in those two functions it just compute the length of the array, it is just an example and can be more complicated than that. Ideally, I want only one function that serve the same purpose (in this case, len) but can take different struct as variable.
type A struct {
id string
}
type AA struct {
ids []A
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
func lengthAA(aa AA) int {
return len(aa)
}
func lengthBB(bb BB) int {
return len(bb)
}
The Go way of doing this would be for both AA and BB to implement a common method. length would then accept an interface that contains the same function signature. Example:
package main
import (
"fmt"
)
type Lengther interface {
Length() int
}
type A struct {
id string
}
type AA struct {
ids []A
}
func (a *AA) Length() int {
return len(a.ids)
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
func (b *BB) Length() int {
return len(b.ids)
}
func length(l Lengther) int {
return l.Length()
}
func main() {
aa := &AA{
ids: make([]A, 10),
}
bb := &BB{
ids: make([]B, 34),
}
fmt.Println(length(aa))
fmt.Println(length(bb))
}
https://play.golang.org/p/DdxP5lFcZi
1- Using two separate receiver methods length() like this working sample code (This is idiomatic Go):
package main
import "fmt"
func (v *AA) length() int {
return len(v.ids)
}
func (v *BB) length() int {
return len(v.ids)
}
func main() {
aa := AA{[]A{A{"id"}, A{"id2"}}}
fmt.Println(aa.length()) // 2
bb := BB{[]B{B{"id", true}, B{"id2", true}}}
fmt.Println(bb.length()) // 2
}
type A struct {
id string
}
type AA struct {
ids []A
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
2- Using one length(aa interface{}) function, like this working sample code (in some use cases this is useful):
package main
import "fmt"
func length(aa interface{}) int {
switch v := aa.(type) {
case AA:
return len(v.ids)
case BB:
return len(v.ids)
}
return -1
}
func main() {
aa := AA{[]A{A{"id"}, A{"id2"}}}
fmt.Println(length(aa)) // 2
bb := BB{[]B{B{"id", true}, B{"id2", true}}}
fmt.Println(length(bb)) // 2
}
type A struct {
id string
}
type AA struct {
ids []A
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
3- Using reflect and one length(v interface{}) function, like this working sample code (in some use cases this is useful):
package main
import "fmt"
import "reflect"
func length(v interface{}) int {
return reflect.ValueOf(v).FieldByName("ids").Len()
}
func main() {
aa := AA{[]A{A{"id"}, A{"id2"}}}
fmt.Println(length(aa)) // 2
bb := BB{[]B{B{"id", true}, B{"id2", true}}}
fmt.Println(length(bb)) // 2
}
type A struct {
id string
}
type AA struct {
ids []A
}
type B struct {
id string
value bool
}
type BB struct {
ids []B
}
output:
2
2
This code wouldn't actually compile since len(aa) would be passing a struct to len which would fail. But I think I get what you're trying to do, and the best way to do it is with the nearest thing Go has to inheritance, which is really just struct embedding.
By making an embeddable struct, and having each of your structs that have that similar feature embed it, you can reduce the line count of the code, though "simplifying" may be a bit of a stretch.
type HasIDs struct {
Ids []string
}
type AA struct {
HasIDs
OtherValues []int
}
type BB struct {
HasIDs
OtherValues []byte
}
At this point both structs AA and BB have the value Ids []string. Now you can give the HasIDs struct a method that both structs should be able to call.
func (hasIds HasIDs) length() {
return len(hasIds.Ids)
}
And call the method on either struct that embeds the struct with the method.
a1 := AA{}
aLength := a1.length()
Here is a working code sample: https://play.golang.org/p/ys_CN_L_cr
The scenario is to pass similar structs with common fields and set those to values passed as params:
package main
type A struct {
Status int
}
type B struct {
id string
Status int
}
// It's okay to pass by value because content is only used inside this
func foo(v interface{}, status int) {
switch t := v.(type) {
case A, B:
t.Status = status // ERROR :-(
}
}
func main() {
a := A{}
foo(a, 0)
b := B{}
b.id = "x"
foo(b, 1)
}
To my dismay, I am getting this error:
➜ test go run test.go
# command-line-arguments
./test.go:15: t.Status undefined (type interface {} has no field or method Status)
What am I doing wrong if the typecast converts interface{} to the underlying type?
Even though A and B both have a status field they are not interchangeable to the type system. You must have separate cases for each of them.
case A:
t.Status = status
case B:
t.Status = status
}
playground link
Alternatively, you could use an actual interface:
type HasStatus interface {
SetStatus(int)
}
type A struct {
Status int
}
func (a *A) SetStatus(s int) { a.Status = s }
func foo(v HasStatus, status int) {
v.SetStatus(status)
}
full example
If you have multiple types that all have a common set of fields you may want to use an embedded struct:
type HasStatus interface {
SetStatus(int)
}
type StatusHolder struct {
Status int
}
func (sh *StatusHolder) SetStatus(s int) { sh.Status = s }
type A struct {
StatusHolder
}
type B struct {
id string
StatusHolder
}
full example