golang struct not implementing interface? - go

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.

Related

Golang: How to embed interface with different type parameters?

The code gives me error: DB redeclared.
Is there any idiomatic way to solve it? Or any work-around?
TIA
type a struct {
DB[int64]
DB[string]
}
type b interface {
DB[int64]
DB[string]
}
type DB[T any] interface {
GetList(query string) ([]T, error)
}
You can't embed the same interface, even with different type parameters. Regardless of how it is instantiated, you are trying to promote into the b interface two methods with the same name GetList and different signatures — given by the different instantiations of DB.
The situation is similar, although not technically the same, for embedding into a struct. In structs, the name of the embedded field is the name of the type — DB —, and a struct can't have two non-blank fields with the same name.
About how to solve this issue, it depends what you want to accomplish.
If you want to convey that "a implements DB with either type parameter" you can embed DB[T] and make a itself generic, and restrict a's type parameters:
type a[T int64 | string] struct {
DB[T]
}
// illustrative implementation of the DB[T] interface
// if you embed DB[T] you likely won't use `a` itself as receiver
func (r *a[T]) GetList(query string) ([]T, error) {
// also generic method
}
This is okay because DB's type parameter is constrained to any, and a's type parameter is more restrictive. This allows you to use a in other generic methods, or choose a specific type upon instantiation, but the implementation of GetList has to be parametrized too.
Otherwise if you need a to have separated methods that return int64 or string, you must give it different names.
Finally, you can embed instances of DB into two interfaces with different names, and then embed those into a instead.
type a struct {
DBStr
DBInt
}
type DBStr interface {
DB[string]
}
type DBInt interface {
DB[int64]
}
This way though the top-level selector isn't available because the method names are still the same. The program compiles, but you'll have to explicitly choose which field to call the method on:
myA := a{ /* init the two fields */ }
res, err = myA.DBStr.GetList(query)
// res is type []string
// or
res, err = myA.DBInt.GetList(query)
// res is type []int64

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.

exported field in unexported struct

Example:
type myType struct {
foo []float64
Name string
}
myType is not exported, but Name field in it is exported.
Does this make sense to do this? Is that considered a bad practice?
I have something like this, and it compiles fine.
I can access the Name field if I create an exported array of myType:
var MyArray []myType = {... some initialization }
fmt.Println(MyArray[0].Name) // Name is visible and it compiles
It is perfectly valid to have unexported structs with exported fields. If the type is declared in another package, the declaration var MyArray []myType would be a compile-time error.
While it is perfectly valid to have an exported function with an unexported return type, it is usually annoying to use. The golint tool also gives a warning for such cases:
exported func XXX returns unexported type pname.tname, which can be annoying to use
In such cases it's better to also export the type; or if you can't or don't want to do that, then create an exported interface and the exported function should have a return type of that interface, and so the implementing type may remain unexported. Since interfaces cannot have fields (only methods), this may require you to add some getter methods.
Also note that in some cases this is exactly what you want: unexported struct with exported fields. Sometimes you want to pass the struct value to some other package for processing, and in order for the other package to be able to access the fields, they must be exported (but not the struct type itself).
Good example is when you want to generate a JSON response. You may create an unexported struct, and to be able to use the encoding/json package, the fields must be exported. For example:
type response struct {
Success bool `json:"success"`
Message string `json:"message"`
Data string `json:"data"`
}
func myHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
resp := &response{
Success: true,
Message: "OK",
Data: "some data",
}
if err := json.NewEncoder(w).Encode(resp); err != nil {
// Handle err
}
}

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