Open ChuntaoLu opened 6 years ago
@ChuntaoLu is this a common pattern you use? I had never seen an anonymous struct returned until just now 😸
@codyoss for me it's commonly found in legacy apps. Where the function arguments or return type is an anonymous struct
I'm actually warming up to this pattern when the opportunity arises.
Consider this example, where I have some low level implementation of a thing:
package lowlevel
type LowLevelThing struct {
}
type LowLevelData struct {
ID string
Value int
}
func (l LowLevelThing) GetData() LowLevelData {
... the implementation ...
}
And now I have some high level module that wants to use the behaviour of the LowLevelThing. But, following the Dependency Inversion principle we're going to define our own interface so we're not coupled to the implementation.
package highlevel
// Look at me, I'm doing dependency inversion so I don't need to know about the implementation!
type Dependency interface {
GetData() lowlevel.LowLevelData // <--- Shoot! Now I know about the implementation!
}
type HighLevelThing struct {
dependency Dependency
}
To avoid this problem, LowLevelData
could just as easily return an anonymous struct with primitives:
func (l LowLevelThing) GetData() struct {
ID string
Value int
} {
... the implementation ...
}
And now the high level module doesn't need to know about the implementation.
//
// Look at me, I'm doing dependency inversion so I don't need to know about the implementation!
type Dependency interface {
GetData() struct { // <-- And I mean it this time!
ID string
Value int
}
}
A struct is preferable over multiple return values, especially when there are multiple of the same type:
type Dependency {
GetData() (string, string, string, string) <-- 🤔 which one was foo, again? Guess I'll go look at the implementation.
}
As a workaround, you can temporarily add a named struct to your implementation and update it to return that named struct before running code gen. Then undo those changes and manually update the mock to return anonymous structs.
Obviously not ideal, but a workaround nonetheless if you don't re-gen often.
Mockgen can't generate mocks for interfaces whose method param or return types are unnamed non-empty structs. For example:
Suppose I have a
foo.go
file whose package import path isfoo
:Running source mode
mockgen -source=foo/foo.go
givesRunning reflect mode
mockgen foo Client
gives