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
}
Related
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.
type A struct {
a1 int
a2 string
}
type B struct {
b1 int
b2 string
}
type C struct {
c1 int
c2 string
}
there are 3 structs, I want put the names into a map as key, and process func as map value
(instead of type-switch)
input arg is a interface, use for loop to judge what struct this interface is. And process this arg by process func in map value.
about:
var funcMap map[structName]func(arg){A:processA, B:processB, C:processC}
func testFunc(arg) {
for k, v in range funcMap {
if k == reflect.TypeOf(arg) {
v(arg)
}
}
}
how can I build this map??? hope code, thanks! (^o^)
You want to index your map on reflect.Type:
type funcMapType map[reflect.Type]func(interface{})
var funcMap funcMapType
then to register a type with a function:
funcMap[reflect.TypeOf(A{})] = func(v interface{}) { log.Println("found A") }
if your function needs to modify the struct, you'll need to register a pointer to the struct type:
funcMap[reflect.TypeOf(&A{})] = func(v interface{}) { log.Println("found *A") }
https://play.golang.org/p/LKramgSc_gz
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
I have following code in Go:
type Foo struct { Id int }
type Bar struct { Id int }
func getIdsFoo(foos []Foo) {
ids = make([]int, len(foos))
// iterate and get all ids to ids array
}
func getIdsBar(bars []Bar) {
ids = make([]int, len(bars))
// iterate and get all ids to ids array
}
Is there a clever way to create a function getIds([]Idable) that can take any struct that have method GetId() implemented?
type Identifiable interface {
GetId() int
}
func GatherIds(ys []Identifiable) []int {
xs := make([]int, 0, len(ys))
for _, i := range ys {
xs = append(xs, i.GetId())
}
return xs
}
sort uses a design patter that might help you.
Create a function that works on an slice-like interface. Then create new types based off of a slice of your concrete types.
Hopefully, the code is more clear than my description. http://play.golang.org/p/TL6yxZZUWT
type IdGetter interface {
GetId(i int) int
Len() int
}
func GetIds(ig IdGetter) []int {
ids := make([]int, ig.Len())
for i := range ids {
ids[i] = ig.GetId(i)
}
return ids
}
type Foo struct{ Id int }
type Bar struct{ Id int }
type FooIdGetter []Foo
func (f FooIdGetter) GetId(i int) int {
return f[i].Id
}
func (f FooIdGetter) Len() int {
return len(f)
}
type BarIdGetter []Bar
func (b BarIdGetter) GetId(i int) int {
return b[i].Id
}
func (b BarIdGetter) Len() int {
return len(b)
}
func main() {
var f = []Foo{{5}, {6}, {7}}
var b = []Bar{{10}, {11}, {12}}
fmt.Println("foo ids:", GetIds(FooIdGetter(f)))
fmt.Println("bar ids:", GetIds(BarIdGetter(b)))
}
There is still a bit more boilerplate than is pleasant, (Go generics... someday). It's greatest advantage is that new methods do not need to be added to Foo, Bar, or any future type you may need to work with.