Accessing Function On Another Struct - go

Using Go 1.11.x with the echo framework.
I have the following struct and function
type AccountController struct {
....
}
func (c *AccountController) ActiveAccountID() int {
....
return 5
}
Now I want to access the ActiveAccountID from another struct, this is how i did it,
type TestController struct {
Account *AccountController
}
func (c *TestController) AddData(ec echo.Context) error {
....
id := c.Account.ActiveAccountID()
....
}
But when I print / use the id var, it just gives me a memory pointer error?
I have tried the account controller to remove the pointer but i still got the memory pointer issue. So what am I doing wrong?
Thanks,

Note the structure of your struct
type TestController struct {
Account *AccountController
}
Account is a pointer. It's inititalized to nil, so if you never set it to point to something, it will always be nil, and you will get a nil pointer dereference error when you try to call a method on it like this
// c *TestController
c.Account.ActiveAccountID()
How/when you set it depends on your use case.
Also depending on your usecase, you can change it from a pointer to an embedded struct
type TestController struct {
Account AccountController
}
This way it's always inside the struct, but if you assign it from somewhere else it will be copied. Depending on your usecase, that might be undesireable.

Related

golang struct not implementing interface?

I am a beginner with go so bear with me on this. I have an interface defined as the following:
type DynamoTable interface {
Put(item interface{}) interface{ Run() error }
}
also I have a Repo struct like so:
type TenantConfigRepo struct {
table DynamoTable
}
and i have a struct dynamo.Table which has a Put function defined like so:
func (table dynamo.Table) Put(item interface{}) *Put
and the Put struct has a Run function as follows:
func (p *Put) Run() error
What I am trying to do is have a generic DynamoTable interface which will then be used for mocking and unit tests. however this is causing an issue with creating a new Repo:
func newDynamoDBConfigRepo() *TenantConfigRepo {
sess := session.Must(session.NewSession())
db := dynamo.New(sess)
table := db.Table(tableName) //=> this returns a type dynamo.Table
return &TenantConfigRepo{
table: table,
}
}
This however is throwing an error like so
cannot use table (variable of type dynamo.Table) as DynamoTable value in struct literal: wrong type for method Put (have func(item interface{}) *github.com/guregu/dynamo.Put, want func(item interface{}) interface{Run() error})
this is very strange for me because from what i see is the interface that has a Run() error should be sufficient for the Put struct since it has the same signature. I am not sure what i am doing wrong here.
Thanks!.
wrong type for method Put (have func(item interface{}) *github.com/guregu/dynamo.Put, want func(item interface{}) interface{Run() error})
your function returns a *Put. The interface expects an interface{Run() error}. A *Put might satisfy this interface, but they're still different types. A function signature returning a type that satisfies that interface is not interchangeable with a function signature returning that interface.
So, start by giving your interface a name. We refer to it in 2 places, and you should avoid anonymous interface (and struct) definitions because they have no inherent benefit and make your code more verbose and less DRY.
type Runner interface{
Run() error
}
Now update DynamoTable to use that interface
type DynamoTable interface {
Put(item interface{}) Runner
}
You say dynamo.Table is outside of your control. But you can create a new type equal to dynamo.Table and then override the put method.
In overridden method, we'l cast our dynamoTable back to dynamo.Table, call the original dynamo.Table.Put, and then return the result.
type dynamoTable dynamo.Table
func (table *dynamoTable) Put(item interface{}) Runner {
return (*dynamo.Table)(table).Put(item)
}
dynamo.Table Can still return a *Put because *Put implements Runner. The return value will be Runner and the underlying type will be *Put. Then the interface will be satisfied, and that error will be fixed.
https://go.dev/play/p/y9DKgwWbXOO illustrates how this retype and override process works.

Refactoring method to be part of an interface

I am an ex python dev sometimes struggling with the explicit nature of Go.
I am trying here to refactor some code in order to be able move a method from one structure to be part of an interface.
But the process seems weird to me, I wish to confirm I am not doing something incorrectly.
I have the following interfaces, structure and methods:
type Executing interface {
Execute()
}
type MyExecuter struct {
attribut1 string
}
//The function I wish to move
func (exe1 *MyExecuter) format() string {
return fmt.sprintf ("formated : %s", exe1.attribut1)
}
func (exe1 *MyExecuter) Execute() {
//Executing
fmt.Println(exe.format())
}
func GetExecuter () Executer{
return MyExecuter{attribut1: "test"}
}
So here I have a generic interface Execute, this interface will be accessed by the object returned by the GetExecuter method.
Now, as part of the implementation of one of my Executer, I want to move the Format method as part of an interface.
So I am doing the following:
type Formatting interface {
format() string
}
type Formatter struct {}
func (formatter *Formatter) format(exe1 *MyExecuter) (string) {
return fmt.sprintf ("formated : %s", exe1.attribut1)
}
So I create a new interface, a new empty structure, and update my function to take as attribute my previous structure.
While this seems to work, it seems to me this is a bit convoluted. Specially the part where I need to add a reference to my initial object as attribute of the method. Am I doing something wrong here, or this is the right way?
Your Executer implementation already implements the Formatting interface:
type Executing interface {
Execute()
}
type Formatting interface {
format() string
}
func (exe1 MyExecuter) format() string {
return fmt.sprintf ("formated : %s", exe1.attribut1)
}
func (exe1 MyExecuter) Execute() {
//Executing
fmt.Println(exe.format())
}
v:=MyExecuter{}
// Here, v implements Executing and Formatting interfaces
One thing to note here: Your code shows pointer receivers. That means the methods are defined for *MyExecuter, but not for MyExecuter. So you have to pass pointers to the struct instance for this to work. Or, as I did above, use the value receivers so the methods are defined for both MyExecuter and *MyExecuter.

How GoLang's typecast to interface implemented by a struct and embedded struct works

I recently came across a code that is doing something I don't understand.
There are multiple structs having the same embedded struct and an interface that defines methods returning pointer to each struct. This interface is implemented by the embedded struct but only 'partially' by the individual structs, as such, each struct only implements the method where the pointer to that struct is returned.
For better understanding, here is the representative code:
type BarStocks interface {
GetVodka() *Vodka
GetMartini() *Martini
GetBourbon() *Bourbon
GetNegroni() *Negroni
GetManhattan() *Manhattan
}
type BaseAttributes struct {
ID uuid.UUID
Quantity float64
CreatedAt time.Time
UpdatedAt time.Time
}
func (e *BaseAttributes) GetVodka() *Vodka {
return nil
}
func (e *BaseAttributes) GetMartini() *Martini {
return nil
}
func (e *BaseAttributes) GetBourbon() *Bourbon {
return nil
}
func (e *BaseAttributes) GetNegroni() *Negroni {
return nil
}
func (e *BaseAttributes) GetManhattan() *Manhattan {
return nil
}
And then each individual struct implements only the method where its pointer is returned, for example:
type Vodka struct {
BaseAttributes
Label string
}
func (v *Vodka) GetVodka() *Vodka {
return v
}
Now in the code, this setup is used to typecast the individual struct to the interface as a pointer, something like this:
func someFunc() BarStocks {
v := Vodka{}
return &v
}
Now I am not too deep into Go yet and so unable to comprehend how the pointer to the struct becomes the same type as the interface.
Thanks in advance for any insight into this.
I'll do my best to answer the question I think you're asking.
The documentation on embedding explains the behavior you're seeing,
There's an important way in which embedding differs from subclassing.
When we embed a type, the methods of that type become methods of the
outer type, but when they are invoked the receiver of the method is
the inner type, not the outer one.
This explains how a Vodka struct, which embeds struct BaseAttributes which implements all of the methods in BarStocks is able to satisfy the interface Barstocks. This excerpt, however, does not explain how we effectively override GetVodka() for our Vodka struct.
To understand this we need to read another excerpt from the documentation.
Embedding types introduces the problem of name conflicts but the rules
to resolve them are simple. First, a field or method X hides any other
item X in a more deeply nested part of the type.
This excerpt explains that If Vodka implements GetVodka() and embeds a struct (BaseAttributes) which also implements GetVodka(), the outer-most definition is the one that takes precedence.
The combination of these behaviors explain how Vodka satisfies the BarStocks interface and has the behavior you see in the example code.
The additional methods missing from Vodka, but present on BarStocks are implemented for BaseAttributes and if the method is missing from Vodka, the method from the embedded strut will be called instead.
Note, methods in an embedded struct will not have access to the parent struct members. Also note, if you wanted to call the embedded struct's method when it has been defined in the parent (as GetVodka is for Vodka) then you would prepend the embedded type's name to the method. For example
myDrink := someFunc()
myDrink.BaseAttributes.GetVodka()
This is obviously not helpful in this case as all of the BaseAttribute methods return nil, but may be helpful in the future.

GO Multiple Pointers

I'm trying to create a function that receives multiple types of struct and add those pointer values to another function.
Example:
type Model1 struct {
Name string
}
type Model2 struct {
Type bool
}
func MyFunc(value ...interface{}) {
OtherFunc(value...)
}
func main() {
MyFunc( new(Model), new(Mode2) );
}
The problem is that OtherFunc only allow &value, &value, etc as parameter. Have some way to pass those values like OtherFunc(&value...)?
I'm not sure this will solve your problem entirely however, the exact thing you requested is a feature in the language. You just have to use composite-literal syntax for instantiation instead of new. So you could do this to pass pointers; MyFunc( &Model{}, &Mode2{} )
Thing is, you're still going to be dealing with an interface{} within MyFunc so I'm not sure that will just be able to call OtherFunc without some unboxing (would probably be a type assertion if you want to get technical).

Golang, call method from struct without variable

Is it possible to call method from struct without variable with this struct type?
//models.go
type MyStruct struct {
id int
name string
}
func (s MyStruct) GetSomeAdditionalData() string {
return "additional data string"
}
//app.go
func main() {
fmt.Println(models.MyStruct.GetSomeAdditionalData()) // not works
var variable models.MyStruct
fmt.Println(variable.GetSomeAdditionalData()) // it worked
}
Or maybe Go have other method to add some data for struct?
Or maybe I select wrong way to do it? :)
You can use a struct literal or a nil pointer.
MyStruct{}.GetSomeAdditionalData()
(*MyStruct)(nil).GetSomeAdditionalData()
To say you can. MyStruct.GetSomeAdditionalData() is called method expression and you must provide first argument of type MyStruct to that call. Argument can be anonymous composite literal MyStruct.GetSomeAdditionalData(MyStruct{}).
Here is working example https://play.golang.org/p/Wc_DjqnpLC . But all that looks not very sensible.
You can define a package function (without any receiver).
It differs from a method, as a method needs a receiver.
func GetSomeAdditionalData() string {
return "additional data string"
}
Which you can call directly, without any instance of the struct MyStruct needed (since you don't need any of MyStruct data anyway):
func main() {
fmt.Println(models.GetSomeAdditionalData())
fmt.Println(GetSomeAdditionalData())
(the second form works if you are in the package models already)

Resources