What is best pattern to reuse Go interface without tripping cyclic dependencies - go

I have this simple package declaration where package "a" defines an interface "A" but I need to use the interface in package "b" for type inference and then the implementation of b.Request() in DoRequest() of "a" this means having to import the package in a cyclic way.
My question is if there is a none complicated approach to this design to avoid compiler cyclic dependency error ?.
NOTE to avoid putting "a" and "b" in the same package
package b
import "a"
func Request(t a.A){
m := t.GetMethod()
payload := t.GetPayload()
}
And Package "a" declaration
package a
import "b"
type A interface {
GetMethod () string
GetPayload () string
}
type ImplimentA struct {
}
func (imp ImplimentA)GetMethod() string{
return ""
}
func (imp ImplimentA) GetPayload() string{
return ""
}
func (imp ImplimentA) DoRequest(){
b.Request(imp)
}

It is considered best practice in go to define interfaces where they are used. So in package b, define an interface with those methods required by the function in package b.
You can still add other functions in package a. The interface from package b can be embedded if you also need to define an interface in package a.
For example:
package b
type AInterface interface {
GetMethod () string
GetPayload () string
}
func Request(t AInterface) {
m := t.GetMethod()
payload := t.GetPayload()
}
Then package A would just contain the implementation.
package a
import "b"
type ImplimentA struct {
}
func (imp ImplimentA) GetMethod() string {
return ""
}
func (imp ImplimentA) GetPayload() string {
return ""
}
func (imp ImplimentA) DoRequest() {
b.Request(imp)
}

Related

Can an interface method accept/return a struct while allowing the use of structs with the same shape to satisfy it?

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

Why can't I call an interface with a collection of methods from the main package

I am really new to golang and I am trying to see how encapsulation really works in go.
I have the following structure
-- package a
-a_core.go
-a.go
-models.go
-- main.go
In models.go I have structs for request and responses for an api call,
a.go has an empty struct, which is private and a public interface, which I want to expose with various methods
a_core.go just has some business logic which would be called in my interface implementation
Then, I have a main.go where I just call the public interface.
code in a.go
package a
type myFunction struct{}
type MyFunc interface {
Create(myData *MyData) (*MyData, error)
Fetch(test string)
Delete(test string)
}
//Concrete implementations that can be accessed publicly
func (a *myFunction) Create(data *MyData) (*MyData, error) {
return nil, nil
}
func (a *myFunction) Fetch(test string) {
}
func (a *myFunction) Delete(test string) {
}
In main.go, I call the interface my first create the MyData pointer with values
data := &a.MyData{
/////
}
result, err := a.MyFunc.Create(data)
I get the following error when I do this,
too few arguments in call to a.MyFunc.Create
cannot use data (variable of type *a.MyData) as a.MyFunc value in argument to a.MyFunc.Create: missing method CreatecompilerInvalidIfaceAssign
Please what am I doing wrong?
Here is an example
Note that names in uppercase are public, in lowercase private (see https://tour.golang.org/basics/3 )
./go-example/main.go
package main
import "go-example/animal"
func main() {
var a animal.Animal
a = animal.Lion{Age: 10}
a.Breathe()
a.Walk()
}
./go-example/animal/animal.go
package animal
import "fmt"
type Animal interface {
Breathe()
Walk()
}
type Lion struct {
Age int
}
func (l Lion) Breathe() {
fmt.Println("Lion breathes")
}
func (l Lion) Walk() {
fmt.Println("Lion walk")
}

How to use interface methods in main file in go?

I have an interface in the service package
databaseService.go
package service
import "gitlab.com/xert/customerservice/internal/database/models"
type CustomerdetailsServiceInterface interface {
// Remove deletes a user by user name from database.
Add()
}
Then I have another service file customerDetailsService.go,where i am implementing the interface methods
type CustomerdetailService struct {
}
func Add(ud *CustomerdetailService) {
fmt.Println("hello")
}
Now when I am trying to use it my main.go
import (
"gitlab.com/xert/customerservice/internal/database/service"
)
func main() {
service.CustomerdetailsServiceInterface.Add() // this is complaining too few arguments
}
How to call the method like this, implement methods in other file?
You have not implemented CustomerdetailsServiceInterface in the first place. Following is the way you can implement it.
type CustomerdetailService struct {}
func (ud *CustomerdetailService) Add() {
fmt.Println("hello")
}
See the following code, hope it will help you understanding interface in go.
package main
import (
"fmt"
)
type CustomerdetailsServiceInterface interface {
Add()
}
type CustomerdetailService struct{}
func (ud *CustomerdetailService) Add() {
fmt.Println("hello")
}
type AnotherCustomerdetailService struct{}
func (ud *AnotherCustomerdetailService) Add() {
fmt.Println("Modified Addition")
}
func main() {
var x CustomerdetailsServiceInterface
x = &CustomerdetailService{}
x.Add()
x = &AnotherCustomerdetailService{}
x.Add()
}
You can not call a method directly on interface but you will need a variable with a type which implements the interface. In the above case it's CustomerdetailService which implements CustomerdetailsServiceInterface.

How to mock a function from another file

I'm playing around with Golang and test cases in it, but it's almost completely different from other testing libraries in other languages (I'm with JS background)
In my file I have:
type MyHandler struct {
myBool bool
Person searchFile.Person
}
And lastly in my third file I have:
type Person interface {
searchFor(name string) (string, error)
}
In my main_test.go I have the following line:
h := &MyHandler{myBool: false} <- how can I mock the searchFor function in Golang
It's just an interface, so simply create a struct that implements the interface (and modify the interface so the method is exported, since it doesn't really make sense to have an unexported method in an interface):
type Person interface {
SearchFor(name string) (string, error)
}
type MockSearcher struct{}
func (m MockSearcher) SearchFor(name string) (string, error) {
return "mock name", nil
}
person := MockSearcher{}
h := &MyHandler{myBool: false, Person: person}
You can embed that interface !
package main
import (
"play.ground/sealed"
)
type sealedStruct struct {
sealed.Interface
}
func (s sealedStruct) sealed() {}
var j sealed.Interface = sealedStruct{}
func main() {
}
-- go.mod --
module play.ground
-- sealed/interface.go --
package sealed
type Interface interface {
sealed()
}
-- sealed/interface_test.go --
package sealed_test
import "test/d/sealed"
type sealedStruct struct {
sealed.Interface
}
func (s sealedStruct) sealed() {}
var j sealed.Interface = sealedStruct{}
https://play.golang.org/p/Ic_TnrLlF_u

Private fields and methods for a struct

In the following test code I would like to have both mytype and the doPrivate method private, so that only members of mytype can access it, but not other types\functions in the scope of the mypackage package.
Can I do this in golang?
package mypackage
type mytype struct {
size string
hash uint32
}
func (r *mytype) doPrivate() string {
return r.size
}
func (r *mytype) Do() string {
return doPrivate("dsdsd")
}
Fields size and hash as well as the doPrivate method should be encapsulated and no other type should have access to them.
In Go, an identifier that starts with a capital letter is exported from the package, and can be accessed by anyone outside the package that declares it.
If an identifier starts with a lower case letter, it can only be accessed from within the package.
If you need members in a type to only be accessed by members of that type, you then need to place that type and its member functions in a separate package, as the only type in that package.
That's not how "privacy" works in Go: the granularity of privacy is the package.
If you really want only the members of mytype to access some fields, then you must isolate the struct and the functions in their own package.
But that's not the usual practice. Whether Go is OOP or not is debatable but clearly the practice isn't to encapsulate the code by a struct like you seem to want to do. Usually a package is small enough to be coherent: if you don't want to access fields from within the package, don't access them.
You can create an interface with the method you wish to expose and only access the object when wrapped into that interface.
package main
type mytype struct {
size string
hash uint32
}
// interface for exposed methods
type myinterface interface {
do() string
}
// constructor (optional)
func newMytype(size string, hash uint32) myinterface {
return &mytype{size, hash}
}
func (r *mytype) doPrivate() string {
return r.size
}
func (r *mytype) do() string {
return r.doPrivate()
}
func main() {
// with constructor
t := newMytype("100", 100)
t.do()
// t.doPrivate() // t.doPrivate undefined (type myinterface has no field or method doPrivate)
// without constructor
t2:= myinterface(&mytype{"100", 100})
t2.do()
// t.doPrivate() // t.doPrivate undefined (type myinterface has no field or method doPrivate)doPrivate)
}
https://play.golang.org/p/awjIIj8Kwms
You cannot do this in Go. Visibility is on a per package level only. But you may split your package into two.
In one module there can be any number of packages.
Public/Private works only across one package.
All public fields, methods and functions starts with uppercase char.
All private fields, methods and functions starts with lowercase char.
To add package to your module or program just create a lowercase folder and add package name to all files inside. Here is the example.
./main.go
./foo/foo.go
./foo/MyStruct.go
file ./foo/foo.go:
package foo
import "fmt"
func SomePublicFuncInFoo() {
somePrivateFuncInFoo()
}
func somePrivateFuncInFoo() {
fmt.Println("somePrivateFuncInFoo call")
}
file ./foo/MyStruct.go:
package foo
import "fmt"
type MyStruct struct {
MyPublicField string // starts with uppercase char
myPrivateField string // starts with lowercase char
}
func NewMyStruct(publicField string, privateField string) *MyStruct {
return &MyStruct{
MyPublicField: publicField,
myPrivateField: privateField,
}
}
func (self *MyStruct) SomePublicMethod() {
self.privateMethod()
}
func (self *MyStruct) privateMethod() {
fmt.Println("MyStruct", self.MyPublicField, self.myPrivateField)
}
file ./main.go:
package main
import (
"fmt"
"{your-module-name}/foo" // this line should be added by your IDE
)
func main() {
foo.SomePublicFuncInFoo()
myStruct := foo.NewMyStruct("string1", "string2")
fmt.Println("myStruct.MyPublicField=", myStruct.MyPublicField)
myStruct.SomePublicMethod()
}
You can have private variables and functions in Go, but the trick is that you simply don't define them in the struct. Bind them to the call stack of a closure, and simply don't return them.
package main
import (
"fmt"
)
type mytype struct {
Do func() string
}
func MyType(size string, hash uint32) mytype {
doPrivate := func() string {
return size
}
return mytype{
Do: func() string {
return doPrivate()
},
}
}
func main() {
instance := MyType("100", 100)
fmt.Println(instance.Do())
}

Resources