How to initialize struct fields - go

How can to initialize any fields in golang types? For example:
type MyType struct {
Field string = "default"
}

You can't have "default" values like that, you can either create a default "constructor" function that will return the defaults or simply assume that an empty / zero value is the "default".
type MyType struct {
Field string
}
func New(fld string) *MyType {
return &MyType{Field: fld}
}
func Default() *MyType {
return &MyType{Field: "default"}
}
Also I highly recommend going through Effective Go.

There is no way to do that directly. The common pattern is to provide a New method that initializes your fields:
func NewMyType() *MyType {
myType := &MyType{}
myType.Field = "default"
return myType
// If no special logic is needed
// return &myType{"default"}
}
Alternatively, you can return a non-pointer type. Finally, if you can work it out you should make the zero values of your struct sensible defaults so that no special constructor is needed.

Related

Why a generic can't be assigned to another even if their type arguments can?

Following code throws a compilation error
cannot use ExampleProps (variable of type Props[Example]) as Props[Generic] value in return statement
// Abstract
type Generic interface {
ID() string
}
type Props[G Generic] struct{}
// Example
type Example struct {
id string
}
func (example Example) ID() string {
return example.id
}
var ExampleProps = Props[Example]{}
// Problem
func Problem() Props[Generic] {
return ExampleProps
}
My question is: as Example implements Generic, why does Go not allow assigning Props[Example] to Props[Generic]?
Instantiating a generic type with different type arguments produces two new different named types.
Note that every time you supply a type argument, including in function arguments or return types, you are instantiating the generic type:
// Props is instantiated with type argument 'Generic'
func Problem() Props[Generic] {
return ExampleProps
}
Therefore Props[Example] is just not the same type as Props[Generic] and you can't use values of one type wherever the other one is expected. It does not matter if the types used as arguments themselves meet some condition for assignability, e.g. interfaces and implementors.
This is also true of generics instantiated with any. The type any is just another static type — alias of interface{}. It's not equal to T and it's not equal to "whatever type".
In simpler terms it’s as if you were using int where string is expected.
What you can do fix it and keep some flexibility is to instantiate Props with a type parameter — whether this makes sense or not depends on how you actually plan to use this function. Anyway, as demonstration:
// adding a field to make this a bit less contrived
type Props[G Generic] struct{ Value G }
// Props instantiated with T, adequately constrained
func Problem[T Generic](v T) Props[T] {
return Props[T]{ Value: v }
}
func main() {
a := Problem(Example{})
fmt.Println(a)
}
Playground: https://gotipplay.golang.org/p/wcDOtJ6z80u

func with struct pointer return value not matching func with interface pointer return value. Can this be made to compile somehow?

There are some generated code I cannot change. They have the general structure like below:
// These structures & methods I cannot change
type NotMyStruct struct {
EmbeddedCaller
}
type EmbeddedCaller struct {
foobar string
}
func (_embeddedCaller *EmbeddedCaller) DoStuff() string {
return "ABC"
}
func NewNotMyStruct() *NotMyStruct {
return &NotMyStruct{
EmbeddedCaller{"blah"},
}
}
The general pattern of the generated code is 1) a parent struct + an embedded struct 2) a method on the embedded struct and 3) a New method that creates the struct.
I have a number of these generated "contracts" and they all have different types, ie NotMyStruct1 NotMyStruct2 etc etc. The embedded structs are all different types as well, ie EmbeddedCaller1, EmbeddedCaller2 etc.
However they all have the same method DoStuff with the same return value. What I would like to do is create a map of some id to the New functions then iterate over each of these and call the DoStuff method. However my code does not compile. it would look something like this if it compiled:
type MyDoStuffInterface interface {
DoStuff() string
}
var instantiations map[string]func()*MyDoStuffInterface{
"1": NewNotMyStruct, //<-- does not compile here because *MyDoStuffInterface doesn't match *NotMyStruct
...
}
for id, instantiationFunc := range instantiations {
instance := instantiationFunc()
instance.DoStuff()
}
Is it possible to do what I'm trying to do? If so how? If not, what is the easiest way to keep things dry?
First, you need to replace *MyDoStuffInterface with MyDoStuffInterface. Pointers to interfaces do have their uses, but nearly all of the time they aren't needed (or correct).
Second, the type of your function (func()*NotMyStruct) doesn't match func()MyDoStuffInterface. (People more experienced in types than me might say that function types in go aren't covariant or something like that).
The best way to solve this second problem is to use a wrapper function that has the correct type. (An alternative is to avoid the type system and use interface{} for your function type and use run-time reflection to call your function).
Here's a full compiling example (playground link). (I had to change your instantiations variable a little because the syntax for initializing a map wasn't correct.)
package main
type NotMyStruct struct {
EmbeddedCaller
}
type EmbeddedCaller struct {
foobar string
}
func (_embeddedCaller *EmbeddedCaller) DoStuff() string {
return "ABC"
}
func NewNotMyStruct() *NotMyStruct {
return &NotMyStruct{
EmbeddedCaller{"blah"},
}
}
type MyDoStuffInterface interface {
DoStuff() string
}
func main() {
var instantiations = map[string](func() MyDoStuffInterface){
"1": func() MyDoStuffInterface { return NewNotMyStruct() },
}
for _, instantiationFunc := range instantiations {
instance := instantiationFunc()
instance.DoStuff()
}
}
Use the following map:
var instantiations = map[string]func()MyDoStuffInterface{
"1": func() MyDoStuffInterface {
return NewNotMyStruct()
},
}
Some notes:
The anonymous "adaptor" function is required because NewNotMyStruct() returns a *NotMyStruct, not a MyDoStuffInterface.
Do not use a pointer to an interface. They are not needed.
Run it on the Go Playground.

Retype code but retain existing interface

I would like to retype an existing type but retain its interface inheritance.
so example code:
interface interface1 {
func interfaceFunc1()
}
type basicStruct struct {
param int
}
type retyped1 basicStruct
type retyped2 basicStruct
func (basicStruct) interfaceFunc1() {
// does stuff
}
func getTyped1() retyped1 {
return basicStruct{param:0}
}
func getTyped2() retyped2 {
return basicStruct{param:1}
}
func main() {
type1 := getTyped1()
type2 := getTyped2()
// These lines do not compile
type1.interfaceFunc1()
type2.interfaceFunc1()
}
Due to a code generation library I am using I can't just have it return basic struct it has to return retyped1 and retyped2.
But I also need to use the interface functions.
Is there anyway to use the interface functions without some silly copy and paste of all the interface functions which do the exact same thing except like 1 if statement in a couple hundred lines?
As Burak Serdar pointed, in golang there is 2 different ways to define type:
type retyped1 struct {
basicStruct
}
Which inherits methods of basicStruct, and
type retyped2 basicStruct
Which creates new struct with same fields as basicStruct, but not it's methods.
For your particular situation you could use type aliases, which is actually just another name for type, so you can reuse it's methods with it:
type retyped1 = basicStruct
If you need to define a type based on an existing struct preserving its interface, use embedding:
type basicStruct struct {
param int
}
type derivedStruct1 struct {
basicStruct
}
type derivedType2 basicStruct
Above derivedStruct1 has the same methods as basicStruct and satisfies the same interfaces, but derivedType2 does not have any methods.

Modify struct fields during instance generation

Foreign application API gives me a list of names in JSON format. I need modify all of those.
But I do not like to write some loop for it (especially after Python using with reflection and stuff)
Is there any method to write something like this in Go?
type MyIncredibleType struct {
Name ModifyName // ModifyName is not a type!
}
func ModifyName(input string) string {
return input + ".com"
}
The expected behavior of this is:
a := MyIncredibleType{Name: "Abracadabra"}
print(a.Name) // Abracadabra.com
This seems pretty straight forward to me, assuming I understand your question correctly:
// ModifyName func
func ModifyName(input string) string {
return fmt.Sprintf("%v.com", input)
}
If you wish to achieve this within the type itself, without modifying (mutating) the internal state:
type MyType sturct {
name string // unexported
}
// accessor func to return name
func (t MyType) Name() string {
return t.name
}
// accessor func to return modified name
func (t MyType) ModifiedName() string {
return fmt.Sprintf("%v.com", t.name)
}
If you want to modify the internal state:
type MyType struct {
name string
}
// mutator func (note the pointer for pass by reference)
func (t *MyType) ModifyName(input string) {
t.name = fmt.Sprintf("%v.com", input)
}
// accessor (note no pointer for pass by value)
func (t MyType) Name() string {
return t.name
}
This is is not possible in GO. That's not how struct works in Go.
type MyIncredibleType struct {
Name ModifyName `json:"name"` // ModifyName is not a type!
}
you can only define Built-in types for your fields of struct or you can define Composite Literal types.
Composite literals construct values for structs, arrays, slices, and
maps and create a new value each time they are evaluated. They consist
of the type of the literal followed by a brace-bound list of elements.
Each element may optionally be preceded by a corresponding key.
Try to create a method receiver of struct which you are using to parse json coming from the api to modify the name. That will let you achieve something similar to what you want.
package main
import (
"fmt"
)
type MyIncredibleType struct {
Name string `json:"name"` // ModifyName is not a type!
}
func(myIncredibleType *MyIncredibleType) ModifyName() string {
return myIncredibleType.Name+".com"
}
func main() {
a := MyIncredibleType{Name: "Abracadabra"}
name := a.ModifyName()
fmt.Printf("%s",name)
}
Playground Example
Or you can pass an interface which will wrap any struct value with name field and then use Type assertion to get the underlying value to modify the same and return the result:
package main
import (
"fmt"
)
type MyIncredibleType struct {
Name string `json:"name"` // ModifyName is not a type!
}
func ModifyName(input interface{}) string{
return input.(interface{}).(string)+".com"
}
func main() {
a := MyIncredibleType{Name: "Abracadabra"}
name := ModifyName(a.Name)
fmt.Printf("%s",name)
}
Working code on Go Playground
For more information also go through Golang method Declarations on how to create receivers.

Conditional variable declaration in golang?

Is it possible to do conditional variable type declaration like this in Golang?
if isAdmin {
var result NormalResult
} else {
var result AdminResult
}
// do something to &result
doSomething(&result)
func doSomething(interface{}) {
// something
}
The above does not work, but the ideas is that normalResult and adminResults are very similar structs and how would I go about doing this?
Thank you!
No, not in this manner. Go being statically typed, needs to know the type information at compile time.
What you could do is declare result as an interface of some type which both AdminResult and NormalResult satisfy. You can then use a type assertion at runtime to decide which type of result it is.
(You also have to declare result outside of the if blocks because Go is block scoped)
type NormalResult struct {
Value int
}
func (r NormalResult) Result() int {
return r.Value
}
type AdminResult struct {
Value int
}
func (r AdminResult) Result() int {
return r.Value
}
type Resulter interface {
Result() int
}
func main() {
isAdmin := true
var r Resulter
if isAdmin {
r = AdminResult{2}
} else {
r = NormalResult{1}
}
fmt.Println("Hello, playground", r)
}
Depending on what kind of similarities, you might have different options.
Using embedded structs
Depending on your structure, you might be able to use embedded structs. Let's say NormalResult is defined like this:
type NormalResult struct {
Name string
Value int
}
And if AdminResult shares the same properties but just adds a few more of them (like UserId), you can choose to embed NormalResult into the AdminResult like this:
type AdminResult struct {
*NormalResult
UserId int64
}
Then you can also declare methods for NormalResult which will be promoted to AdminResult as well:
func (r *NormalResult) doSomething() {
// Doing something
}
Edit
And, no, it is not possible to have conditional types in Go as you suggested. A variable can only be of one type, be it NormalResult, AdminResult or interface{}

Resources