Iterating through struct values from embedded struct - go

I have the following struct
type ChartOpts struct {
Name mypackage.Sometype
Repo mypackage.Anothertype
mypackage.SomeSpecialStructType
}
Then I create the following receiver for mypackage.SomeSpecialStructType as follows:
func (c SomeSpecialStructType) BindFlags() {
fields := reflect.TypeOf(c)
values := reflect.ValueOf(c)
num := fields.NumField()
for i := 0; i < num; i++ {
switch v := values.Field(i).Interface().(type) {
case OrmosFlag:
fmt.Printf("%#T\n", v)
//v.BindPersistentFlag(cobCom)
log.Println("HERE")
default:
log.Println("ERROR")
}
}
}
As (perhaps) becomes evident from the code, I want to leverage embedding so that the embedded type (that I was expecting to have access to the outer struct fields) can perform some operations on them.
The code does not works given that num is 0 here (makes since given that SomeSpecialStructType has zero fields, just a receiver)
I know I can just copy-paste the specific receiver on each and every ChartOpts struct I create (there will be plenty of them coming) but just trying to be DRY here.

Embedding is not inheritance. When you embed a struct type into another, you are essentially composing a new type, not extending the embedded type.
type Inner struct {
X int
}
type Outer struct {
Inner
}
Above, Outer is a struct containing Inner. When you declare a variable of type Outer, you can access the fields of the Inner struct by:
x:=Outer{}
x.Inner.X=1
x.X=1
So in fact this is no different from:
type Outer struct {
Inner Inner
}
with the difference that the field name is omitted. So you can shortcut the field name when you access the variables.
in short: there is no way a method of an inner struct can access the embedding struct. If you need that, have a constructor method for the outer struct that sets a pointer in the inner struct. Also, pass around a pointer to the returned struct. If you copy the struct, the pointer needs to be adjusted.
type Outer struct {
Inner
}
type Inner struct {
X int
o *Outer
}
func NewOuter() *Outer {
ret:=&Outer{}
ret.outer=ret
return ret
}

Related

Wrapped structs referencing

I am little consfused about value type struct wrapped by pointer type struct.
Example:
package main
import (
"fmt"
)
type A struct {
id int
B
}
func (a *A) setId(val int) {
a.id = val
}
type B struct {
name string
}
func (b B) setNameViaValue(val string) {
b.name = val
}
func (b *B) setNameViaPointer(val string) {
b.name = val
}
func main() {
a := new(A)
a.setId(1)
a.setNameViaValue("valuename")
fmt.Println(a)
a.setNameViaPointer("pointername")
fmt.Println(a)
}
I would expect that referencing through pointer type A struct(which addresses concrete memory) that wraps B value type struct will set inner value no matter what kind of refence to B is used (B/*B). This is also related to type definition. Can anyone also explain what is different when I define it like this? Is there any usecase scenario?
type A struct {
id int
*B
}
Why doesn't setNameViaValue end up setting the name
If you declare a method with a value (non-pointer) receiver, then that method cannot "modify" the receiver cause it will actually receive a copy.
That's why the "name" is not set as you expected with the setNameViaValue method.
If you want to be able to set the name of B in that way, only setNameViaPointer is an option.
You can read more about the differences between method and value receivers here:
https://tour.golang.org/methods/8
Why can you actually invoke the inner struct methods on the outer struct
That's because you "embedded" the inner struct in the outer one.
When you include a struct type name without giving it a field name, then all of the "inner" struct methods and fields are "promoted" to the outer one.
That means you can call a.setNameViaValue and it will be equivalent to doing a.B.setNameViaValue.
Is there any difference if I embedded as a pointer
If you define A this way:
type A struct {
id int
*B
}
Then:
The "setNameViaValue" will still not work (that's only related to the method being defined over a value instead of a pointer receiver, it has nothing to do with how A references B).
You will need to initialize B explicitly when creating an A object, otherwise *B will end up being nil. (if you reference it as a value, it will be initialized as an empty B)
You can change what *B points to later on (if it was a value, then it will always reference the same "value")

Immutable Struct in Golang

Is it possible to define an immutable struct in Golang? Once initialized then only read operation on struct's field, no modification of field values. If so, how to do that.
It is possible to make a struct read-only outside of its package by making its members non-exported and providing readers. For example:
package mypackage
type myReadOnly struct {
value int
}
func (s myReadOnly) Value() int {
return s.value
}
func NewMyReadonly(value int) myReadOnly{
return myReadOnly{value: value}
}
And usage:
myReadonly := mypackage.NewMyReadonly(3)
fmt.Println(myReadonly.Value()) // Prints 3
There is no way to mark fields/variables as read only in a generic way. The only thing you could do is marking fields/variable as unexported (first letter small) and provide public getters to prevent other packages editing variables.
There is no way to define immutable structures in Go: struct fields are mutable and the const keyword doesn't apply to them. Go makes it easy however to copy an entire struct with a simple assignment, so we may think that passing arguments by value is all that is needed to have immutability at the cost of copying.
However, and unsurprisingly, this does not copy values referenced by pointers. And the since built-in collections (map, slice and array) are references and are mutable, copying a struct that contains one of these just copies the pointer to the same underlying memory.
Example :
type S struct {
A string
B []string
}
func main() {
x := S{"x-A", []string{"x-B"}}
y := x // copy the struct
y.A = "y-A"
y.B[0] = "y-B"
fmt.Println(x, y)
// Outputs "{x-A [y-B]} {y-A [y-B]}" -- x was modified!
}
Note : So you have to be extremely careful about this, and not assume immutability if you pass a parameter by value.
There are some deepcopy libraries that attempt to solve this using (slow) reflection, but they fall short since private fields can't be accessed with reflection. So defensive copying to avoid race conditions will be difficult, requiring lots of boilerplate code. Go doesn't even have a Clone interface that would standardize this.
Credit : https://bluxte.net/
if you write a functional struct by golang, it must be an immutable struct, eg
you can write maybe struct definite
type Maybe[T any] struct {
v T
valid bool
}
func (m Maybe[T]) Just() T {
return m.v
}
func (m Maybe[T]) Nothing() bool {
return m.valid == false
}
func Just[T any](v T) Maybe[T] {
return Maybe[T]{
v: v,
valid: true,
}
}
func Nothing[T any]() Maybe[T] {
return Maybe[T]{
valid: false,
}
}
the maybe struct is a immutable struct

Using (sub)struct located in other package in Datastore

I haven't been able to find any information related to this.. let's say you call an API and save the resulted json into a struct in package Foo, like this:
package foo
type FooData struct {
A string `json:"c"`
B int `json:"c"`
C int64 `json:"c"`
}
Then you have your own model package:
package bar
import (
"github.com/bla/bla/foo"
)
type BarData struct {
A float
Foo foo.FooData
}
Is this possible? Is there anything negative about doing it this way? The reason is the structs are over a hundred lines, so I feel it would be wasteful to duplicate it.
Also, what if I only want to index in B? Then I can just change it to:
type FooData struct {
A string `datastore:",noindex" `json:"c"`
B int `json:"c"`
C int64 `datastore:",noindex" `json:"c"`
}
?
Edit: Just to make it clear, my intention is to save the BarData struct in Datastore
The Go Datastore package has some documentation relating to this - https://cloud.google.com/appengine/docs/standard/go/datastore/reference#hdr-Structured_Properties
"Structured Properties
If the struct pointed to contains other structs, then the nested or embedded structs are flattened. For example, given these definitions:
type Inner1 struct {
W int32
X string
}
type Inner2 struct {
Y float64
}
type Inner3 struct {
Z bool
}
type Outer struct {
A int16
I []Inner1
J Inner2
Inner3
}
then an Outer's properties would be equivalent to those of:
type OuterEquivalent struct {
A int16
IDotW []int32 `datastore:"I.W"`
IDotX []string `datastore:"I.X"`
JDotY float64 `datastore:"J.Y"`
Z bool
}
If Outer's embedded Inner3 field was tagged as datastore:"Foo" then the equivalent field would instead be: FooDotZ bool datastore:"Foo.Z".
If an outer struct is tagged "noindex" then all of its implicit flattened fields are effectively "noindex"."
So there shouldn't be any issues with you storing nested structs, just be aware that they will be flattened in datastore. It also mentions the no indexing, saying any field inherits a "noindex" from its parent struct. I don't see why your "noindex" tagging of the inner fields wouldn't work.

What are the second pair of braces in this Golang struct?

var cache = struct {
sync.Mutex
mapping map[string]string
} {
mapping: make(map[string]string),
}
This looks like a struct with an embedded field sync.Mutex but I can't get my head around the second set of braces. It compiles and executes but what's up? Why does the label on the make instruction matter (it does) and the comma? Thanks...
The example you have is equivalent to:
type Cache struct {
sync.Mutex
mapping map[string]string
}
cache := Cache{
mapping: make(map[string]string),
}
Except in your example you do not declare a type of Cache and instead have an anonymous struct. In your example, as oppose to my Cache type, the type is the entire
struct {
sync.Mutex
mapping map[string]string
}
So think of the second pair of braces as the
cache := Cache{
mapping: make(map[string]string),
}
part.
make is a built in function that works similarly to C's calloc() which both initialize a data structure filled with 0'd values, in Go's case, certain data structures need to be initialized this way, other's (for the most part structs) are initialized with 0'd values automatically. The field there is needed so that the compiler now's cache.mapping is a empty map[string]string.
The comma there is part of Go's formatting, you can do Cache{mapping: make(map[string]string)} all on one line, but the moment the field's assignment is on a different line than the opening and closing braces, it requires a comma.
This is called a "struct literal" or an "anonymous struct" and is, in fact, how you always create structs in Go, it just may not be immediately obvious since you might be used to creating new types for struct types to make declaring them a bit less verbose.
An entire struct definition is actually a type in Go, just like int or []byte or string. Just as you can do:
type NewType int
var a NewType = 5 // a is a NewType (which is based on an int)
or:
a := 5 // a is an int
and both are distinct types that look like ints, you can also do the same thing with structs:
// a is type NewType (which is a struct{}).
type NewType struct{
A string
}
a := NewType{
A: "test string",
}
// a is type struct{A string}
a := struct{
A string
}{
A: "test string",
}
the type name (NewType) has just been replaced with the type of the struct itself, struct{A string}. Note that they are not the same type (an alias) for the purpose of comparison or assignment, but they do share the same semantics.

How to set default values in Go structs

There are multiple answers/techniques to the below question:
How to set default values to golang structs?
How to initialize structs in golang
I have a couple of answers but further discussion is required.
One possible idea is to write separate constructor function
//Something is the structure we work with
type Something struct {
Text string
DefaultText string
}
// NewSomething create new instance of Something
func NewSomething(text string) Something {
something := Something{}
something.Text = text
something.DefaultText = "default text"
return something
}
Force a method to get the struct (the constructor way).
From this post:
A good design is to make your type unexported, but provide an exported constructor function like NewMyType() in which you can properly initialize your struct / type. Also return an interface type and not a concrete type, and the interface should contain everything others want to do with your value. And your concrete type must implement that interface of course.
This can be done by simply making the type itself unexported. You can export the function NewSomething and even the fields Text and DefaultText, but just don't export the struct type something.
Another way to customize it for you own module is by using a Config struct to set default values (Option 5 in the link). Not a good way though.
One problem with option 1 in answer from
Victor Zamanian is that if the type isn't exported then users of your package can't declare it as the type for function parameters etc. One way around this would be to export an interface instead of the struct e.g.
package candidate
// Exporting interface instead of struct
type Candidate interface {}
// Struct is not exported
type candidate struct {
Name string
Votes uint32 // Defaults to 0
}
// We are forced to call the constructor to get an instance of candidate
func New(name string) Candidate {
return candidate{name, 0} // enforce the default value here
}
Which lets us declare function parameter types using the exported Candidate interface.
The only disadvantage I can see from this solution is that all our methods need to be declared in the interface definition, but you could argue that that is good practice anyway.
There is a way of doing this with tags, which
allows for multiple defaults.
Assume you have the following struct, with 2 default
tags default0 and default1.
type A struct {
I int `default0:"3" default1:"42"`
S string `default0:"Some String..." default1:"Some Other String..."`
}
Now it's possible to Set the defaults.
func main() {
ptr := &A{}
Set(ptr, "default0")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=3 ptr.S=Some String...
Set(ptr, "default1")
fmt.Printf("ptr.I=%d ptr.S=%s\n", ptr.I, ptr.S)
// ptr.I=42 ptr.S=Some Other String...
}
Here's the complete program in a playground.
If you're interested in a more complex example, say with
slices and maps, then, take a look at creasty/defaultse
From https://golang.org/doc/effective_go.html#composite_literals:
Sometimes the zero value isn't good enough and an initializing constructor is necessary, as in this example derived from package os.
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
f := new(File)
f.fd = fd
f.name = name
f.dirinfo = nil
f.nepipe = 0
return f
}
What about making something like this:
// Card is the structure we work with
type Card struct {
Html js.Value
DefaultText string `default:"html"` // this only works with strings
}
// Init is the main function that initiate the structure, and return it
func (c Card) Init() Card {
c.Html = Document.Call("createElement", "div")
return c
}
Then call it as:
c := new(Card).Init()
I found this thread very helpful and educational. The other answers already provide good guidance, but I wanted to summarize my takeaways with an easy to reference (i.e. copy-paste) approach:
package main
import (
"fmt"
)
// Define an interface that is exported by your package.
type Foo interface {
GetValue() string // A function that'll return the value initialized with a default.
SetValue(v string) // A function that can update the default value.
}
// Define a struct type that is not exported by your package.
type foo struct {
value string
}
// A factory method to initialize an instance of `foo`,
// the unexported struct, with a default value.
func NewFoo() Foo {
return &foo{
value: "I am the DEFAULT value.",
}
}
// Implementation of the interface's `GetValue`
// for struct `foo`.
func (f *foo) GetValue() string {
return f.value
}
// Implementation of the interface's `SetValue`
// for struct `foo`.
func (f *foo) SetValue(v string) {
f.value = v
}
func main() {
f := NewFoo()
fmt.Printf("value: `%s`\n", f.GetValue())
f.SetValue("I am the UPDATED value.")
fmt.Printf("value: `%s`\n", f.GetValue())
}
One way to do that is:
// declare a type
type A struct {
Filed1 string
Field2 map[string]interface{}
}
So whenever you need a new variable of your custom defined type just call the NewA function also you can parameterise the function to optionally assign the values to the struct fields
func NewA() *A {
return &A{
Filed1: "",
Field2: make(map[string]interface{}),
}
}
for set default values in Go structs we use anonymous struct:
Person := struct {
name string
age int
city string
}{
name: "Peter",
age: 21,
city: "Noida",
}
fmt.Println(Person)
Structs
An easy way to make this program better is to use a struct. A struct is a type which contains named fields. For example we could represent a Circle like this:
type Circle struct {
x float64
y float64
r float64
}
The type keyword introduces a new type. It's followed by the name of the type (Circle), the keyword struct to indicate that we are defining a struct type and a list of fields inside of curly braces. Each field has a name and a type. Like with functions we can collapse fields that have the same type:
type Circle struct {
x, y, r float64
}
Initialization
We can create an instance of our new Circle type in a variety of ways:
var c Circle
Like with other data types, this will create a local Circle variable that is by default set to zero. For a struct zero means each of the fields is set to their corresponding zero value (0 for ints, 0.0 for floats, "" for strings, nil for pointers, …) We can also use the new function:
c := new(Circle)
This allocates memory for all the fields, sets each of them to their zero value and returns a pointer. (*Circle) More often we want to give each of the fields a value. We can do this in two ways. Like this:
c := Circle{x: 0, y: 0, r: 5}
Or we can leave off the field names if we know the order they were defined:
c := Circle{0, 0, 5}
type Config struct {
AWSRegion string `default:"us-west-2"`
}

Resources