Passing function as parameter: Incompatible types in Golang - go

Fairly new to Go, but still no idea why this isn't working. There's a function (A) being defined and passed as argument to another function (B), which takes A's arguments in the exact correct way (AFAIK):
// Function A
func writeToPumps(keys []interface{}, job *health.Job, startTime time.Time) {..}
// Function B
func GenerateDemoData(start time.Time, days int, orgId string, writer func(keys []interface{}, job *health.Job, startTime time.Time)) {...}
//calling Function B with Function A as last argument:
demo.GenerateDemoData(time.Now().AddDate(0, 0, -30), 30, buildDemoData, writeToPumps)
That yields:
./main.go:191:56: cannot use writeToPumps (type func([]interface {}, *"tyk-pump/vendor/github.com/gocraft/health".Job, time.Time)) as type func([]interface {}, *"github.com/TykTechnologies/tyk-pump/vendor/github.com/gocraft/health".Job, time.Time) in argument to demo.GenerateDemoData
How can I fix this?
EDIT
Import section in main.go:
import (
"github.com/TykTechnologies/tyk-pump/analytics/demo"
"time"
"os"
"fmt"
"github.com/gocraft/health"
"gopkg.in/vmihailenco/msgpack.v2"
"github.com/TykTechnologies/logrus"
"github.com/TykTechnologies/logrus-prefixed-formatter"
"github.com/TykTechnologies/tyk-pump/analytics"
"github.com/TykTechnologies/tyk-pump/pumps"
"github.com/TykTechnologies/tyk-pump/storage"
"github.com/TykTechnologies/tykcommon-logger"
"gopkg.in/alecthomas/kingpin.v2"
)
Other useful info:
GOPATH: /home/nilsnolde/dev/go/uni
Project structure:
../uni/src/
|
--tyk-pump/
|
--vendor/
main.go
...

Your code should live under /uni/src/github.com/TykTechnologies/tyk-pump. Since it doesn't, when your code internally references that package hierarchy, it re-vendors your code, generating duplicate import paths.
So the fix is probably just to move /uni/src/tyk-pump to /uni/src/github.com/TykTechnologies/tyk-pump then re-import all your vendored packages.

The file in which function A is defined is likely not the same file where you have B defined. The two files are both importing health, where the definition of health.Job seems to live.
However they seem to be using a different import path, therefore GO thinks that the definition of health.Job isn't the same.
You should check the import statements in both places and make them the same. If they are already the same, there is something in the project setup that needs to be adjusted, but there isn't enough context to figure out what that might be.

Related

Go Doc is indenting/grouping functions unexpectedly. What is causing it?

Go Doc is indenting/making a group without me knowingly telling it to.
Here is a screenshot from my browser showing the problem. The four Parse functions should not be indented:
What is causing this behaviour?
I've tried searching for indents/subsections/grouping in Go Docs but I've not found anything beside feature requests. I'm sure the answer to my question is in the documentation somewhere but I can't find it as I don't have the correct vocabulary.
I'm relatively new to Go and Go Doc, so I'm assuming the answer is something simple which I've overlooked.
Here is an extract of my code. Please let me know if I need to share more code.
status.go
package synop
// Status codes returned when parsing Blocks.
type Status int64
const (
VALID Status = iota
NO_DATA
// code omitted
)
// Other functions omitted
cloudwind_block.go
package synop
import (
"strings"
)
/*
Extract cloud cover from the cloud-wind block, Cxxxx.
Cloud, C, is the first digit of the block. Cloud over is given in [okta]:
*/
func ParseCloud(block string) (okta int, s Status) {
slice := [2]int{0, 1}
return parseIfValid(block, slice, str2int)
}
/*
Extract wind direction from from the cloud-wind block, xDDxxx.
Direction, DD, are the second and third digits.
*/
func ParseDir(block string) (dir string, s Status) {
slice := [2]int{1, 3}
return parseIfValid(block, slice, getDir)
}
// Other functions omitted
I have another file, blocks.go, which has almost the same structure as status.go and it does not cause this behaviour. I also don't know if the problem is caused by the preceding type Status or something in the cloudwind_block.go file.
I'm using // for single-line documentation and /* */ for multi line. I've tried making this consistent on the off chance and, as expected, it had no effect.
The reason for the grouping and indentation is that those functions are considered "constructors" of the type under which they are grouped/indented.
https://go.dev/doc/comment#func (if you scroll down a bit, you'll see this):
This example also shows that top-level functions returning a type T or pointer *T, perhaps with an additional error result, are shown alongside the type T and its methods, under the assumption that they are T’s constructors.

How to avoid import cycles in mock generation?

Simple example.
I have package xxx. This package contains:
struct A
interface B which is a field of A
struct C which is an argument in method of B
type A struct {
SomeField B
}
type B interface {
SomeMethod(c C)
}
Now imagine I want to create unit test for structure A and mock dependency B. For creating mock I am using mock generator. All mocks are stored in the common "mocks" folder.
The problem is that generated mock has a dependency on xxx package. This is happening because SomeMethod of interface B has argument xxx.C.
Whenever I try to import my mock structure in a_test.go it fails because of cycle import problem. xxx package importing mocks package in the a_test.go. and mocks package imports xxx package in my generated mock.
I need a peace of advice, what is the best workaround for this? Maybe my approach is not idiomatic enough. Where do you store your mocks?
You need to put your test under a different package.
a.go is under package xxx
a_test.go is under package xxx_test
a_mock.go is under package xxx_mock
This way a_test.go will be dependent on xxx and xxx_mock and will not cause dependency cycle.
Also, a.go and a_test.go can be under the same folder, like this:
xxx/
- a.go
- a_test.go
mock/
- a_mock.go
Since
interface
struct
user code
unit test for the user code
are all in the same package, the interface should be considered as "in-package" interface, which is invisible for code in other package. So, the mock for this interface should be IN THE SAME PACKAGE as the interface itself.
Conclusion:
interface
struct
user code
unit test for the user code
mock for the interface
PUT ALL OF THEM IN THE SAME PACKAGE.
So put the mock code generated by gomock into the same package as the interface, but not "mock" package. Example(windows version):
mockgen -source=.\foo\bar.go -destination=.\foo\bar_mock.go -package=foo
Compiling a_test.go as different package (ex. a_test) will resolve the cirucular import issue.
This is the io_test.go example from go language source. Associate question with example by replacing package xxx with package io and a_test with io_test.
//io_test.go
package io_test
import{
. "io" //wildcard import
}
// io_test code
However there wont be access to non-exported type in package io. To make the non-exported type to exported type we could add a file export_test.go and define a exported and assign non-exported type to exported type.
//export_test.go
package io
// exported for test
var IOExportedType= ioNonExportedType
Use a top level package that all other packages import from. Put your interfaces there.
For instance:
domain/
interfaces.go
a/
mock.go
b/
mock.go
c/
mock.go
a, b and c should import from domain so they don't have any dependencies on each other. You will use duck typing to implement the interfaces of the domain package in your mocks.
Here's an actual use case using your example:
domain/interfaces.go:
type A interface {
Foo()
}
type B interface {
Bar() string
}
type C interface {
Baz() string
}
a/mock.go:
type A struct {
SomeField domain.B
}
// ...
b/mock.go:
type B struct {
SomeMethod(c domain.C)
}
// ...
c/mock.go:
type C struct {}
// ...
That should compile just fine, because all the mocks import from the top level domain package, and they all implement the respective interfaces.
In case of avoiding self referencing in Go 1.17
Add this arg
-self_package github.com/xxx
So
mockgen -source=<srcName>.go \
-package <pkgName> \
-self_package github.com/<user>/<repo>/<pkgName> \
-destination <dest>.go

Golang Circular import structs

My code is simple.
Project/
main.go
pokemons/
pokemon.go
pokeTrainers/
pokeTrainer.go
I have some Pokemon trainers which are defined like this :
package pokeTrainers
import "../pokemons"
type PokeTrainer struct {
name string
pokemon []Pokemon
}
And some Pokemon :
package pokemons
import "../pokeTrainers"
type Pokemon struct {
name string
pokeTrainers PokeTrainer
}
main package is:
package main
import (
"fmt"
"./pokemons"
"./pokeTrainers"
)
func main() {
fmt.Printf("ERROR CIRCULAR IMPORT")
As always when I have an error, I copy-paste it on google. I learn what's a circular import and how people fix it with interface to use methods from another package without import it. But in my case, the problem is not to use methods but a real Type defined in another package.
So you will probably say: "Man you are dumb ! You just have to put everything on the same package and it's fine !"
Sorry, I come from Java and I would like that my code stays clean. ;)
I saw this link which suggest to use a third party packages ? But you have to imagine that I don't have only pokemon and pokeTrainer, I have many more packages with a type inside and a lot of methods..
What do you think ? How can I fix this error proprelly ? I'm a beginner in Go
Either use a single package, so no import is needed.
Or designate one of your packages to be a "master", and put "everything" that is needed from both packages into this "master", and so only the other package needs to import "master" by definition (and "master" doesn't need to import the other).
Or you have to create a 3rd package for the stuff that is needed from both, and your 2 current packages only have to import this 3rd common package.
P.S. And don't use relative imports. Always use the complete package path.
I suggest you using interface for Pokemon. Perhaps you will add a several type of a pokemon and PokeTrainer should to train each one.
Example:
poketrainer.go
package pokeTrainers
type IPokemon interface {
train() error
}
type PokeTrainer struct {
name string
pokemon []IPokemon
}
pokemon.go
package pokemons
import "github.com/pokemonWorld/pokeTrainers"
type Pikachu struct {
name string
sensei *PokeTrainer
}
func (o *Pikachu) train() error {
// your code here
}
One extra point of a recommendation - use a pointer of structure but not as a value.

Is there any tangible downside to using static type constructors in go?

I've always found the package.New() syntax in go rather awkward to work with.
The suggestion is that if a package holds only a single type, using package.New() to create an instance; if multiple types exist, using package.NewBlah().
http://golang.org/doc/effective_go.html#package-names
However, this approach falls down if you if you have an existing package with a New() api, adding a new external type to the package breaks the api, because you must now rename this NewFoo(). Now you have to go and change anything that uses New(), which is deeply irritating.
...and I'm just discontent with the aesthetic of writing this:
import "other"
import "bar"
import "foo"
o := other.New() // <-- Weird, what type am I getting? No idea.
x := bar.New()
y := foo.NewFoo() // <-- Awkward, makes constructor naming look inconsistent
z := foo.NewBar()
So, recently I've been using this pattern instead:
x := foo.Foo{}.New() // <-- Immediately obvious I'm getting a Foo
y := foo.Bar{}.New() // <-- Only an additional 3 characters on NewBar{}
o := other.Foo{}.New() // <-- Consistent across all packages, no breakage on update
Where the module is defined something like this:
package foo
type Foo struct {
x int
}
func (s Foo) New() *Foo {
// Normal init stuff here
return &s // <-- Edit: notice the single instance is returned
}
type Bar struct {
}
func (Bar) New() *Bar {
return &Bar{} // <-- Edit: Bad, results in double alloc. Not like this.
}
Godoc seems to work fine with it, and it seems more obvious and consistent to me, without additional verbosity.
So, question: Is there any tangible downside to this?
Yes, it has a downside. This approach may generate unnecessary garbage - depending on how good the optimization of a specific Go compiler implementation is.
It's not terribly idiomatic and may if done badly create excess garbage as you note. Essentially you are just creating an Init method for your object. I don't use a lot of constructors myself tending to prefer having valid zero values for my objects and only using a constructor if that doesn't hold true.
In your case I think I'd just stop calling the method new and instead call it Init or Setup to better reflect what it's doing. That would avoid giving people the wrong idea about what it's doing.
Edit:
I should have been more detailed here. Calling the method Init or Setup and then using it on a Zero Value would better reflect what is going on to the consumer. eg
f := &foo{}
f.Init()
This avoids the excess garbage and gives you an initializer method as you describe.

Any way to alias a function name to '_'?

In Go, is there any circumstance where the gettext short-form of:
_("String to be translated.")
can be used? One of those times where I'm fairly certain the answer is 'no', but asking just in case I've overlooked something. I'm thinking the best that can be achieved is:
import . "path/to/gettext-package"
...
s := gettext("String to be translated.")
since underscore has a very specific meaning, and attempting to define a function named '_' results in the compile-time error "cannot use _ as value".
No. The blank identifier
... does not introduce a new binding.
IOW, you can declare "things" named _ but you cannot refer to them in any way using that "name".
However, one can get close to the goal:
package main
import "fmt"
var p = fmt.Println
func main() {
p("Hello, playground")
}
(also here)
ie. you can bind any (local or imported) function to a variable and later invoke the function through that variable, getting rid of the package prefix - if you think that's handy. IMO not, BTW.

Resources