Golang struct definition patterns - go

I'm currently playing with Go, was wondering what are the patterns for defining the data types. For example take the Bencode and representing it as a Go data structure.
like in Haskell
data BEncode = BInt Integer
| BString L.ByteString
| BList [BEncode]
| BDict (Map String BEncode)
in C, we can do something like this
struct Bencoding;
typedef struct ListNode {
struct Bencoding *cargo;
struct ListNode *next;
} ListNode;
typedef struct DictNode {
char *key;
struct Bencoding *value;
struct DictNode *next;
} DictNode;
typedef struct Bencoding {
BType type;
union {
long long val; // used when type == BInt
ListNode *list; // used when type == BList
char *str; // used when type == BString
DictNode *dict;
} cargo; // data
} Bencoding;
what is the best way to define these kinds of data structures in Golang. Are there any patterns / good practices with Golang.

Like this?
type BEncodeType int
const (
TypeBInt BEncodeType = iota
TypeBString
TypeBList
TypeBDict
)
type BEncode interface {
Type() BEncodeType
Val() interface{}
}
type BInt int
func (n *BInt) Type() BEncodeType {
return TypeBInt
}
func (n *BInt) Val() interface{} {
return n
}
type BString string
func (n *BString) Type() BEncodeType {
return TypeBString
}
func (n *BString) Val() interface{} {
return n
}
type BList []BEncode
func (n *BList) Type() BEncodeType {
return TypeBList
}
func (n *BList) Val() interface{} {
return n
}
type BDict map[string]BEncode
func (n *BDict) Type() BEncodeType {
return TypeBDict
}
func (n *BDict) Val() interface{} {
return n
}

Related

Golang idiom for passing multiple argument types

I am new to learning Go and have a question around defining an argument that could be one of two types.
Take the code:
type Thing struct {
a int
b int
c string
d string
}
type OtherThing struct {
e int
f int
c string
d string
}
func doSomething(t Thing/OtherThing) error {
fmt.println(t.d)
return nil
}
As the structs have no functions I cannot write an interface for them at present.
So what is the Go idiomatic thing to do here? Is it just to bolt on a random function to the structs and write an interface or something else?
Thanks for the help...
Declare a interface with the common functionality for the two types. Use the interface type as the argument type.
// Der gets d values.
type Der interface {
D() string
}
type Thing struct {
a int
b int
c string
d string
}
func (t Thing) D() string { return t.d }
type OtherThing struct {
e int
f int
c string
d string
}
func (t OtherThing) D() string { return t.d }
func doSomething(t Der) error {
fmt.Println(t.D())
return nil
}
You can give two structs some shared functionality by composing them both from a base struct:
package main
import (
"fmt"
)
// Der gets d values.
type Der interface {
D() string
}
type DBase struct {
d string
}
func (t DBase) D() string { return t.d }
type Thing struct {
DBase
a int
b int
c string
}
type OtherThing struct {
DBase
e int
f int
c string
}
func doSomething(t Der) error {
fmt.Println(t.D())
return nil
}
func main() {
doSomething(Thing{DBase: DBase{"hello"}})
doSomething(OtherThing{DBase: DBase{"world"}})
}
DBase provides the field (d) and satisfies the Der interface the same way for both Thing and OtherThing. It does make the struct literal a little longer to define.
You can use an interface{} argument and the reflect package to access the common field. Many people will say that this approach is not idiomatic.
func doSomething(t interface{}) error {
d := reflect.ValueOf(t).FieldByName("d").String()
fmt.Println(d)
return nil
}
Try an example on the playground.

Can't access embedded struct when I pass an instance of my outer structinto a slice of an interface, which the outer struct implements

package main
import (
"fmt"
)
type shape struct {
name string
}
type square struct {
shape
length int
}
type twoDimensional interface {
area() int
}
func (s square) area() int {
return s.length * s.length
}
func main() {
s1 := square{
length: 2,
}
s1.name = "spongebob"
allSquares := []twoDimensional{
s1,
}
fmt.Println(allSquares[0].name)
}
This is giving me the following error:
./prog.go:36:27: allSquares[0].name undefined (type twoDimensional has no field or method name)
I'm confused about what's going on here. Type square is embedded with type shape, and type square also implements the twoDimensional interface.
If I pass an instance of square into a slice of twoDimensionals, how come I can no longer access type shape from my square?
The interface itself does not have .name attribute. You need to use type assertion allSquares[0].(square) as the following:
package main
import (
"fmt"
)
type shape struct {
name string
}
type square struct {
shape
length int
}
type twoDimensional interface {
area() int
}
func (s square) area() int {
return s.length * s.length
}
func main() {
s1 := square{
length: 2,
}
s1.name = "spongebob"
allSquares := []twoDimensional{
s1,
}
fmt.Println(allSquares[0].(square).name)
}

How to append items to a map[string][]Struct

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
}

Generic method to iterate over collection (slice) of structs

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.

How do I hold onto a factory function in Go?

I'm trying to hold a function that will return new instances of a type implementing a particular interface in a struct. Here's a stripped down example:
package main
type Adder interface {
Add(Adder)
Val() int
}
type NewAdder func() Adder
type number int
type NewHolder struct {
newFunc NewAdder
}
func (me *number)Add(it Adder) {
*me += number(it.Val())
}
func (me *number)Val() int {
return int(*me)
}
func newAdder() *number {
return (*number)(new(int))
}
func main() {
var holder NewHolder
holder.newFunc = NewAdder(newAdder)
}
When I try to compile it, it says cannot convert newAdder (type func() *number) to type NewAdder. So what's the go-like way to accomplish my goal?
Here's a Python example of what I'm trying to do, just for reference:
class NewStuffMaker(object):
def __init__(self, new):
self.new = new
def make_new():
return []
obj = NewStuffMaker(make_new)
new_lst = obj.new()
Ideally, I'd like to be able to hold a bunch of these functions (or structs containing the functions and some other data) in a slice. Is that an unreasonable thing to do?
package main
type Adder interface {
Add(Adder)
Val() int
}
type FuncAdder func() Adder
type Holder struct {
FuncAdder
SomeOtherData string
}
type number int
func (n *number) Add(a Adder) {
*n += number(a.Val())
}
func (n *number) Val() int {
return int(*n)
}
func NumberAdder() Adder {
return Adder(new(number))
}
func main() {
var holders []Holder
var holder Holder
holder.FuncAdder = NumberAdder
holder.SomeOtherData = "SomeOtherData"
holders = append(holders, holder)
}

Resources