Modularizing golang package using interfaces - go

I am learning golang and in the process of trying to wrap my head around interfaces and how to use them for unit testing.
I currently have a main.go which calls another package: packageName that I wrote.
Currently in main.go, I use package like this:
package main
import (
...
./packageName
)
func main () {
var1 := "test"
str1 := packageName.Func1(var1)
var2 := "sample"
str2 := packageName.Func2(var2)
}
and packageName is:
package packageName
import (
"os"
"net/http"
)
func Func1 (str string) string {
resp,err := http.get("www.something.com")
return resp.string() // or something along these lines
}
func Func2 (str string) string {
sampleFile, sampleFileErr := os.OpenFile(str, os.O_CREATE, 0600)
return "done"
}
After reading about testing and interfaces, it seems like I have to rewrite everything using interfaces so it can be unit tested (more modular).
My question, is how do I do this properly. Do I put all external library calls into one interface, and then make all functions in the package part of one struct?
example:
package packageName
import (
"os"
"net/http"
)
type External interface {
urlGet(string) (*http.Response, error)
OpenFile(string, int, os.FileMode) (*os.File, error)
}
func New() ExternalSt {
return ExternalSt{}
}
struct ExternalSt struct {}
func (ExternalSt) urlGet(str string) *http.Response {
return http.get(str)
}
func (ExternalSt) OpenFile (str string, flags int, perms os.FileMode) (*os.File, error) {
return os.OpenFile(str, flags, perms)
}
func (e ExternalSt) Func1 (str string) string {
resp,err := e.urlGet("www.something.com")
// do some other stuff
return resp.string() // or something along these lines
}
func (e ExternalSt) Func2 (str string) string {
sampleFile, sampleFileErr := e.OpenFile(str, os.O_CREATE, 0600)
// do some other stuff
return "done"
}
and then main would be:
package main
import (
...
./packageName
)
func main () {
test := packageName.New()
var1 := "test"
str1 := test.Func1(var1)
var2 := "sample"
str2 := test.Func2(var2)
}
With the above implementation I don't even need the interface, but i'm guessing it would come in handy when Im doing unit tests and need to implement my own mock functions under a test interface to call during testing.
OR
should I create an interface with all the external functions, but pass the new instance I create into the functions as a parameter similar to here. Ex:
package main
import (
...
./packageName
)
func main () {
var test packageName.External
var1 := "test"
str1 := packageName.Func1(test, var1)
var2 := "sample"
str2 := packageName.Func2(test, var2)
}
and the package:
package packageName
import (
"os"
"net/http"
)
type External interface {
urlGet(string) (*http.Response, error)
OpenFile(string, int, os.FileMode) (*os.File, error)
}
func New() ExternalSt {
return ExternalSt{}
}
struct ExternalSt struct {}
func (ExternalSt) urlGet(str string) *http.Response {
return http.get(str)
}
func (ExternalSt) OpenFile (str string, flags int, perms os.FileMode) (*os.File, error) {
return os.OpenFile(str, flags, perms)
}
func Func1 (e External, str string) string {
resp,err := e.urlGet("www.something.com")
// do some other stuff
return resp.string() // or something along these lines
}
func Func2 (e External, str string) string {
sampleFile, sampleFileErr := e.OpenFile(str, os.O_CREATE, 0600)
// do some other stuff
return "done"
}
The second option doesn't seem to work very well as I keep getting an error
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation
but I need more of an understanding of interfaces.
Regardless, I cannot seem to understand which of the 2 options are best to go with.
Or are both these options completely wrong.
NOTE: I'm aware the syntax of the above code is incorrect, and will probably not compile, just looking for an approach here.

Related

Can I create a function with same signature as another?

I need to create a function that wraps an inner function, and has exactly the same signature as the inner function. I am fearing that this is not possible since Go does not support generics, but perhaps it is achievable using reflect? The following is the pseudo-go I would like to have:
func myFunc(a int, b string) (string, error) {
return string(a) + b, nil
}
func wrapInner(inner interface{}) interface{} {
argTypes := argsOf(inner)
returnTypes := returnsOf(inner)
wrapper := func(args argTypes) returnTypes {
// do something with inner's args
modArgs := doSomething(args)
ret := inner(modArgs)
// do something with the return
modRet := doSomething(ret)
}
return wrapper
}
wrapped := wrapInner(myFunc)
val, err := wrapped(1, "b")
The pseudo-code is full of errors, but the idea is that wrapInner has no clue about the signature of inner. However, it is able to inspect the signature (using, perhaps, reflect?) and creates a function that adds logic to inner and has exactly the same signature as inner. Is this possible?
What you are trying to achieve is the middleware pattern. It is commonly implemented with interfaces. You would have to manually implement the middleware function for every function you wish to annotate.
Here is an example:
package main
import (
"fmt"
"strconv"
)
type Service interface {
myFunc(a int, b string) (string, error)
}
type implService struct{}
func (s implService) myFunc(a int, b string) (string, error) {
return strconv.Itoa(a) + b, nil
}
type loggingMiddleware struct {
next Service
}
func (s loggingMiddleware) myFunc(a int, b string) (string, error) {
fmt.Println(a, b)
return s.next.myFunc(a, b)
}
func main() {
var myservice Service = &implService{}
myservice = &loggingMiddleware{
next: myservice,
}
result, err := myservice.myFunc(1, "a") // prints 1 a
fmt.Println(result, err) // prints 1a <nil>
}

Can golang plugins be used for factory functions?

I have the following code in a golang plugin module:
plug.go
package main
import "fmt"
var (
Thing = New("first thing")
ThingFactory = thingFactory{}
)
type thing struct {
i int
s string
}
func New(s string) thing {
return thing{s: s}
}
func (t *thing) Say() string {
t.i++
return fmt.Sprintf("%s - %d", t.s, t.i)
}
type thingFactory struct{}
func (t thingFactory) Make(s string) thing {
return New(s)
}
it is compiled as a .so object and used in another program:
main.go
package main
import (
"fmt"
"plugin"
)
func main() {
p, err := plugin.Open("../plug/plug.so")
if err != nil {
panic(err)
}
symbol, err := p.Lookup("Thing")
if err != nil {
panic(err)
}
thing := symbol.(Sayer)
fmt.Println(thing.Say())
symbol, err = p.Lookup("ThingFactory") // <-problems start here
if err != nil {
panic(err)
}
factory := symbol.(GetSayer)
madeThing := factory.Make("how about me?")
fmt.Println(madeThing.Say())
fmt.Println(madeThing.Say())
}
type Sayer interface {
Say() string
}
type GetSayer interface {
Make(string) Sayer
}
I'm able to lookup the Thing, and call Say() on it, but the second interface conversion panics:
first thing - 1
panic: interface conversion: *main.thingFactory is not main.GetSayer: missing method Make
even though the runtime recognizes the first symbol as a Sayer it doesn't recognize that thingFactory obviously has a Make() method, which should return something that is also a Sayer.
Am I missing something obvious here?
The first problem is that in your plugin thingFactory (more precicely *thingfactory) does not have a method described in your main app's GetSayer interface:
Make(string) Sayer
You have:
Make(string) thing
So (first) you have to change thingFactory.Make() to this:
type Sayer interface {
Say() string
}
func (t thingFactory) Make(s string) Sayer {
th := New(s)
return &th
}
After this it still won't work. And the reason for this is because the plugin's Sayer type is not identical to your main app's Sayer type. But they must be the same in order to implement your main app's GetSayer interface.
One solution is to "outsource" the Sayer interface to its own package, and use this common, shared package both in the plugin and in the main app.
Let's create a new package, call it subplay:
package subplay
type Sayer interface {
Say() string
}
Import this package and use it in the plugin:
package main
import (
"fmt"
"path/to/subplay"
)
var (
Thing = New("first thing")
ThingFactory = thingFactory{}
)
type thing struct {
i int
s string
}
func New(s string) thing {
return thing{s: s}
}
func (t *thing) Say() string {
t.i++
return fmt.Sprintf("%s - %d", t.s, t.i)
}
type thingFactory struct{}
func (t thingFactory) Make(s string) subplay.Sayer {
th := New(s)
return &th
}
And also import and use it in the main app:
package main
import (
"fmt"
"path/to/subplay"
"plugin"
)
func main() {
p, err := plugin.Open("../plug/plug.so")
if err != nil {
panic(err)
}
symbol, err := p.Lookup("Thing")
if err != nil {
panic(err)
}
thing := symbol.(subplay.Sayer)
fmt.Println(thing.Say())
symbol, err = p.Lookup("ThingFactory")
if err != nil {
panic(err)
}
factory := symbol.(GetSayer)
madeThing := factory.Make("how about me?")
fmt.Println(madeThing.Say())
fmt.Println(madeThing.Say())
}
type GetSayer interface {
Make(string) subplay.Sayer
}
Now it will work, and output will be:
first thing - 1
how about me? - 1
how about me? - 2
See related questions:
go 1.8 plugin use custom interface
How do Go plugin dependencies work?
Your plugin Make method should return a Sayer object not thing
type Sayer interface {
Say() string
}
func (t *thingFactory) Make(s string) Sayer {
return New(s)
}

How do I find implementations of a function type?

In Go, it's possible to create function types (https://golang.org/ref/spec#Function_types) like this
type Printer func(s string)
How can I find all of the functions which satisfy this type? For example, if I had the file below, how could I find out that consolePrinter is a Printer?
package main
import "fmt"
func main() {
printToScreen(consolePrinter)
}
// Printer defines a function that prints a string.
type Printer func(s string)
func printToScreen(p Printer) {
p("Hello")
}
// consolePrinter is a Printer (the function signature is identical).
func consolePrinter(s string) {
fmt.Println(s)
}
I tried out guru, but the implements feature doesn't seem to support function types.
guru implements ./main.go:#134
/Users/adrian/go/gurutest/main.go:10.6-10.12: signature type Printer implements only interface{}
You are looking for functions that are assignable to Printer.
The guru tool does not support an "assignable to" query.
You can write a program to find functions that are assignable to Printer using the go/types package. Follow the tutorial to type check code and use AssignableTo to find the functions.
If you are only interested in finding functions declared at package level in gofmted code, then searching your code with a regexp might be good enough. This approach is not accurate, but is simple to do in many editors or the command line.
Here consolePrinter is not of type Printer it is required to declare consolePrinter to be of type Printer.You see console.Printer is a function with same underlying type that's why it can be pass to printToScreen which takes Printer type. Have a Look at the difference with their types
package main
import (
"fmt"
"reflect"
)
func main() {
printToScreen(consolePrinter)
fmt.Println(reflect.TypeOf(consolePrinter)) // Prints func(string) as its type
}
// Printer defines a function that prints a string.
type Printer func(s string)
func printToScreen(p Printer) {
var consoleprint Printer // declare to be of type Printer
fmt.Println(reflect.TypeOf(consoleprint)) // Prints main.Printer
p("Hello")
}
// consolePrinter is a Printer (the function signature is identical).
func consolePrinter(s string) {
fmt.Println(s)
}
Playground Example
Working example, based on Thundercat's answer. guru would need to do something like this to provide support for looking up suitable functions to pass in (e.g. implementations of http.HandleFunc).
package main
import (
"fmt"
"go/ast"
"go/importer"
"go/parser"
"go/token"
"go/types"
"log"
)
const hello = `package main
import "fmt"
const x = 1;
func main() {
fmt.Println("Hello, world")
}
// Printer defines a function that prints a string.
type Printer func(s string)
func consolePrinter(s string) {
fmt.Println(s)
}
`
func main() {
fset := token.NewFileSet()
// Parse the input string, []byte, or io.Reader,
// recording position information in fset.
// ParseFile returns an *ast.File, a syntax tree.
f, err := parser.ParseFile(fset, "hello.go", hello, 0)
if err != nil {
log.Fatal(err) // parse error
}
// A Config controls various options of the type checker.
// The defaults work fine except for one setting:
// we must specify how to deal with imports.
conf := types.Config{Importer: importer.Default()}
// Type-check the package containing only file f.
// Check returns a *types.Package.
pkg, err := conf.Check("cmd/hello", fset, []*ast.File{f}, nil)
if err != nil {
log.Fatal(err) // type error
}
names, signatures := getFunctionTypes(pkg)
for i, name := range names {
fmt.Println("Functions which implement", name)
for _, implementor := range getFunctionsWhichImplement(signatures[i], pkg) {
fmt.Println(implementor)
}
}
}
func getFunctionTypes(pkg *types.Package) (names []string, signatures []*types.Signature) {
for _, name := range pkg.Scope().Names() {
o := pkg.Scope().Lookup(name)
if _, isType := o.(*types.TypeName); !isType {
continue
}
var sig *types.Signature
var isFunc bool
if sig, isFunc = o.Type().Underlying().(*types.Signature); !isFunc {
continue
}
signatures = append(signatures, sig)
names = append(names, name)
}
return
}
func getFunctionsWhichImplement(sig *types.Signature, pkg *types.Package) (fns []types.Object) {
for _, name := range pkg.Scope().Names() {
o := pkg.Scope().Lookup(name)
if _, isType := o.(*types.TypeName); isType {
continue
}
var csig *types.Signature
var isFunc bool
if csig, isFunc = o.Type().Underlying().(*types.Signature); !isFunc {
continue
}
if types.AssignableTo(sig, csig) {
fns = append(fns, o)
}
}
return
}
The output of this code is shown below:
Functions which implement Printer
func cmd/hello.consolePrinter(s string)
I'm sure there are better ways for the specific case of printing, but in general you may be better to take a more idiomatic go approach of using interfaces.
Declare an interface and types that implement the interface:
type StringPrinter interface {
PrintString(string)
}
type Console struct {
// console specific stuff
}
func (c *Console) PrintString(s string) {
// Printing code
}
type Paper struct {
// paper specific stuff
}
func (p *Paper) PrintString(s string) {
// Printing code
}
Then to print in different ways you can access through an interface in a generic way:
func main() {
var sp StringPrinter
sp = &Console{ /* member inits */ }
sp.PrintString("Hello on console")
sp = &Paper{ /* member inits */ }
sp.PrintString("Hello on paper")
}
You will be able to use guru on this form of code to find objects that implement the StringPrinter interface.

Call Method Expression with Pointer to Struct as Receiver

There is func someFunc(v interface{}, fn interface{}) where v is a pointer to struct (say *A) and fn is a method expression (say (*A).method()). How to call fn with v as parameter (using reflect)?
It's possible to do with reflect.Value.Call(), however it's pretty cumbersome, especially if you need to do something with the return value. But here's a basic example:
package main
import (
"fmt"
"reflect"
)
type Foo struct {
Bar string
}
func concrete(foo *Foo) {
fmt.Printf("Foo: %#v\n", foo)
}
func someFunc(v interface{}, fn interface{}) {
f := reflect.ValueOf(fn)
arg := reflect.ValueOf(v)
f.Call([]reflect.Value{arg})
}
func main() {
foo := Foo{"Bar"}
someFunc(&foo, concrete)
}
// Output: Foo: &main.Foo{Bar:"Bar"}
https://play.golang.org/p/ED6QdvENxti
If you want to call a method of a struct by name, we need to revise it just a bit:
type Foo struct {
Bar string
}
func (f *Foo) Concrete() {
fmt.Printf("Foo: %#v\n", f)
}
func callByName(v interface{}, fn string) {
arg := reflect.ValueOf(v)
f := arg.MethodByName(fn)
f.Call([]reflect.Value{})
}
func main() {
foo := Foo{"Bar"}
callByName(&foo, "Concrete")
}
Notice that in this case the method value is already bound to the struct instance, so we don't need to pass it anything as an argument.
So to the challenge of using reflect to call a method without knowing name and being a method of the same type, as op (orignally) addressed, I have come up with a very, very ugly and unsafe way.
package main
import (
"fmt"
"reflect"
"runtime"
"strings"
)
func getFName(v reflect.Value) string {
return runtime.FuncForPC(v.Pointer()).Name()
}
func callMethod(a,fn interface{}) {
fname:=getFName(reflect.ValueOf(fn))
parts:=strings.Split(fname,".")
name:=strings.TrimSuffix(parts[len(parts)-1],"-fm")
reflect.ValueOf(a).MethodByName(name).Call(nil)
}
func (s *a) Tst() {
fmt.Println(s)
}
type a struct { p string }
func main() {
x,y:=a{"Good"},a{"Bad"}
callMethod(&x,y.Tst)
}
Playground: https://play.golang.org/p/QgrGhI5DC3p
I would like to know a better way that does not rely on how runtime.FuncForPc formats methods (which is not version-safe), but this is the best I have. Please do tell me any ideas to improve it.

Using callbacks and functions as a type in go

I am attempting to create a sort of function that is similar to the Express (NodeJS) route method in Go:
app.get("route/here/", func(req, res){
res.DoStuff()
});
In this example I want "foo" (the type) to be the same as the anonymous function in the above method. Here is one of my failed attempts using Go:
type foo func(string, string)
func bar(route string, io foo) {
log.Printf("I am inside of bar")
// run io, maybe io() or io(param, param)?
}
func main() {
bar("Hello", func(arg1, arg2) {
return arg + arg2
})
}
How might I fix my dilemma? Should I not use a type and use something else? What are my options?
You are on the right track - creating a type for a func in the context you are using it adds clearer design intent and additional type safety.
You just need to modify your example a bit for it to compile:
package main
import "log"
//the return type of the func is part of its overall type definition - specify string as it's return type to comply with example you have above
type foo func(string, string) string
func bar(route string, io foo) {
log.Printf("I am inside of bar")
response := io("param", "param")
log.Println(response)
}
func main() {
bar("Hello", func(arg1, arg2 string) string {
return arg1 + arg2
})
}
package main
import (
"fmt"
"log"
)
type foo func(string, string)
func bar(route string, callback foo) bool {
//...logic
/* you can return the callback to use the
parameters and also in the same way you
could verify the bar function
*/
callback("param", "param")
return true
}
func main() {
fmt.Println("Hello, playground")
res := bar("Hello", func(arg1, arg2 string) {
log.Println(arg1 + "_1")
log.Println(arg2 + "_2")
})
fmt.Println("bar func res: ", res)
}

Resources