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.
Related
I would like to create a library that exports a function that defines its own dependencies without consuming types from an external package (excluding std lib).
The issue is, if my dependency is an interface type with a method that returns a struct, consumers have to use the exact struct declared in the interface.
In situations where I have two or more libraries, each sharing the same interface signature however each package defining its own interface (interface segregation), they conflict when it comes to methods that return struct types.
package mylibrary
type Result struct {
Value string
}
type IFoo interface {
Foo() Result
}
func DoFoo(f IFoo) {
f.Foo()
}
With the above code, anyone implementing this library must use the mylibrary.Result struct exactly to satisfy the IFoo interface.
In the case where I have multiple packages defining the interfaces of their own dependencies, this can become difficult and or impossible
See the following example: https://replit.com/#davidalsh/UsedCarefreeBrain#main.go
// main.go
// Creating an object that satisfies the contract roughly
import (
packagea "main/package-a"
packageb "main/package-b"
)
type Result struct {
Message string
}
type Foo struct {}
// Even though Result is the same shape, this needs to
// return either packagea.Result or packageb.Result
func (*Foo) Foo() Result {
return Result{}
}
func main() {
dep := Foo{}
packagea.DoFoo(dep) // Foo does not implement packagea.IFoo
packageb.DoFoo(dep) // Foo does not implement packageb.IFoo
}
This seems like a strange limitation. Methods on an interface can return types like string, int, []int, etc but not a struct.
Should I be returning an interface with getters/setters from IFoo.Foo, e.g.?
type IResult interface {
Message() string
}
type IFoo interface {
Foo() IResult
}
What if I would like to use a struct as an argument for a function? Should I also only accept an interface of getters?
interface IUserDetails {
FirstName() string
LastName() string
Age() int
}
func SayHello(user IUserDetails) {
fmt.Println("Hello", user.FirstName())
}
Or is there a better way?
Define a type in a third package:
common/common.go
package common
type Result struct {
Message string
}
Use this package in all other packages:
main.go
package main
import (
"main/common"
packagea "main/package-a"
packageb "main/package-b"
)
type Foo struct{}
func (*Foo) Foo() common.Result {
return common.Result{}
}
func main() {
dep := &Foo{}
packagea.DoFoo(dep)
packageb.DoFoo(dep)
}
package-a/packagea.go
package packagea
import "main/common"
type IFoo interface {
Foo() common.Result
}
func DoFoo(f IFoo) {
f.Foo()
}
Run the program on the Go Lang Playground
I'm working on a project that would require some level of abstraction on some data and I would like to keep the packages that use the data as independent as possible so I can swap things out in the future.
Here are 2 possible ways that I thought of, one is having a common data interface and have all the places import it. The other is to have each package define its own interfaces and do a type assertion.
Which is the most Go/general way of doing it?
// Importing interface
// src/model
type IData interface {
myint() int
}
// src/dataextractor
import src/model
type DataExtractor struct {
foo() IData
}
// src/service
import src/model
type ServiceDataExtractor interface {
foo() IData
}
type Service struct {
extractor ServiceDataExtractor
}
func (s Service) serve() {
v = s.extractor.foo()
// do stuff with v
}
vs
// type assertion
// src/dataextractor
type DataExtractorData struct{}
func (d DataExtractorData) myint()int {}
type DataExtractor struct {
foo() interface{} {
reutrn DataExtractorData{}
}
}
// src/service
type ServiceData interface {
myint() int
}
type ServiceDataExtractor interface {
foo() interface{}
}
type Service struct {
extractor ServiceDataExtractor
}
func (s Service) serve() {
data := s.extractor.foo()
v, ok := data.(ServiceData)
// do stuff with v
}
Here's the simple rules to keep in mind. An interface type should be declared in the package that wants to receive that interface type. To satisfy an interface, you don't have to import it. All you need to do is declare the methods as are specified by the interface.
When do you use interfaces? Typically, when you have a field, or parameter, that you want to be able to accept multiple data types, and you can do all you need to do with it by calling methods. How do you determine what goes in the interface? You simply ask yourself: "What methods would I need to call on this value to make use of it?"
The only seemingly meaningful method in your example is myint() int, and the only place it seems you intend to use it is in Service.
type Service struct {
extractor interface {
myint() int
}
}
func (s Service) serve() {
s.extractor.myint()
}
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.
I've inherited some code that looks like this:
type FooWrapper struct {
Stuffer interface{ GetStuff() *grpc.Stuff }
Thinger interface{ GetThing() *grpc.Thing }
Widgeter interface{ GetWidget() *grpc.Widget }
// many more like these
}
func NewFooWrapper(v proto.Message) FooWrapper {
var w FooWrapper
w.Stuffer, _ = v.(interface{ GetStuff() *grpc.Stuff })
w.Thinger, _ = v.(interface{ GetThing() *grpc.Thing })
w.Widgeter, _ = v.(interface{ GetWidget() *grpc.Widget })
// many more like these
return w
}
func (w FooWrapper) GetStuff() *grpc.Stuff {
if w.Stuffer == nil {
return nil
}
return w.Stuffer.GetStuff()
}
// many more methods like this one
We can see that this code does the following:
It declares a FooWrapper struct with a bunch of anonymous interface fields, one for each method that can possibly exist in any implementation of proto.Message.
The NewFooWrapper constructor is converting v to each one of those anonymous interface types, discarding the error. Thus, if the type boxed in v does not have the GetXXX method, the related field in w will simply be nil
FooWrapper getters check if the corresponding field is nil and if it's not, it invokes the method on the boxed value.
To me this seems a quite verbose way of implementing a type switch, though I'm not sure this is idiomatic Go code.
However I guess it could be useful in cases where v had to be passed to multiple unrelated methods, causing the type switch to be copy-pasted everywhere (it's not the case of the code I got here).
Is this code equivalent to a type switch, in practice?
What are the advantages in using this pattern instead of a type switch?
In a word, "no", it's not idiomatic. But of course that doesn't mean it's "wrong".
Although given that the anonymous interface types are repeated, it seems pretty silly to do that, rather than a named type.
If I had inherited that code, I would immediately change it.
And with that exact code sample in mind, I would also re-define my struct to use embedded interfaces:
type Stuffer interface { GetStuff() *grpc.Stuff }
type Thinger interface { GetThing() *grpc.Thing }
type Widgeter interface { GetWidget() *grpc.Widget }
type FooWrapper struct {
Stuffer
Thinger
Widgeter
// many more like these
}
I have 3 structures that are similar about 70%. So I'd like to extract some common part and create some extensions with specific methods and fields.
Final structure will work as follows:
method .Start() from Common is called
Start() calls method .Name() from specific part the latter return a string
the returned result is being processed in (*Common).Process(), sometimes it should call specific's Format()
But! Specific part have to call Common part's method, for example GetVerbosity()
Like this:
package common
type Common struct {
Specificer
}
func (c *Common) Start() {
...
name := Specific.Name()
}
func (c *Common) GetVerbosity() {...}
type Specificer interface {
Name() string
Format() string
}
And specific part:
package specific1
// should implement common.Specificer interface
type Specific1 struct {
// unexported fields
}
func (s *Specific1) Name() string {...}
func (s *Specific1) Format() string {
// How to call it???
Common.Method()
}
This is similar to some frameworks - when another code calls your code, and also you call it's code.
How to implement this better? And how to create new structures?
I tried:
Embed Specific to Common, and embed vise versa:
type Common struct {
Specificer
}
type Specific1 struct {
common.Common
...
}
// But this is little bit insane:
func NewSpecific1() *common.Common {
var s = Specific1{}
return &common.Common{Specificer: &s}
}
Define 2 interfaces: Commoner and Specificer. And combined interface:
package common
type CommonSpecificer interface {
Commoner
Specificer
}
type Common struct {...} // implements all the methods from Commoner
func New() *Common {...}
//////
package specific1
type Specific1 struct { // implements all the methods from common.Specificer
Common
...
}
func NewSpecific1() *Specific1 {
c := common.NewCommon(...)
s := &Specific1{Common: c}
return s
}