GoLang - types from different scopes - go

If you are getting an error like:
interface conversion: interface {} is *purchase.User, not *purchase.User (types from different scopes)
It appears that you are sending the correct type since the expected and actual type in the error message are exactly the same.

You may have created another type pointing to the *purchase.User in another package (purchase2) and that is the type your method is looking into receiving but you are sending (purchase.User)
For example:
in purchase package
type User struct {
firstName string
lastName string
}
in purchase2 package
import purchase
type User purchase.User
Check which type are you referring to.

Alternate cause for this: you have somehow imported the package twice, with two different import paths. This is unlikely to be seen except in unusual circumstances (AST code rewriters, non-standard vendoring, etc).
If you are importing the same package with different paths, there is a very good chance that you're doing something very wrong. Stop it :P

Related

Why are unexported struct fields purposely not marshalled in the json package

In the json package if you want to utilize tags to marshall and unmarshall structs the field must be exported. I always thought this was a limitation on the reflect package but it seems to be explicitly rejected here.
I would like to know what I am missing or the design choices behind this as it creates one of the following issues normally.
Exporting more fields than I want allowing users to change values without using potential getters and setters.
A lot of extra code if you chose to solve the above problem by making a second identical struct just for tag usage and make it unexported.
Here is a playground of code being able to read unexported tags.
Edit: Better playground thanks to #mkopriva

Go: How to resolve dependency for structs passing between two packages as params?

Don’t know what’s the best practice to structure this so I don’t have cyclic dependency, I have a user package which exposes UserService which takes a store because it needs to access database, but it also has some structs
package user
type UserParams struct {
Client util.HTTPExecutor
Store store.Store
...
}
func NewUserService(params *UserServiceParams) *UserService {...}
type User struct {
ID int32 `db:"id" json:"id"`
Name string `db:"name" json:"name"`
}
At the same time I have a store package which has an interface takes some user structs and save into the database.
package store
type Store interface {
UpdateUser(ctx context.Context, u *user.User) error
}
Does it make more sense to
Move User struct into store package (latter might end up a lot of those structs for different product components)
Move User struct into a separate common package so both packages have access to it
Move User struct into a package userstruct under user package
Thank you!
First of all, this question is slightly subjective because it depends largely on your project and how your project lays out. That being said, here is what I would do if I were you.
Consider adding a types package. A types package would rarely be dependent on anything else, but everything would be dependent on the types package. Then both your store and services packages could import the types package without any concern for cyclical dependencies.
Arrows denote a dependency/import

Can I reference an imported type without using dot notation

Consider the following interface definition:
package repos
import (
resources "unit/pkg/resources"
)
type IRepo interface {
fetch(int32) (resources.IResource, error)
update(resources.IResource) (resources.IResource, error)
new() resources.IResource
create(resources.IResource) (resources.IResource, error)
delete(int32) error
}
Is there a way to 'use' the imported package (in the sense of C++ namespaces), so that I don't need to explicitly name it using dot notation each time I reference one of its types (IResource)
(TBH - this may just mean that IResource belongs in the repos package and not in resources)
You can prefix the import declaration with the name . to import all of its identifiers:
package repos
import (
. "unit/pkg/resources"
)
However, import . is almost never the appropriate solution. If new identifiers are added to the resources package in the future, they can collide with existing identifiers in the repos package and break your build.
Furthermore, the fact that the package name is redundant with the type name may indicate that either the package or the types within that package should have a better name (see the Package names blog post for much more detail).
In this case, perhaps the abstraction boundary between resources and repos is doing more harm than good. What kind of resources are you dealing with here? Could the Resource type be moved into some higher-level package?
Finally, I would note that the IRepo interface seems very large and likely out-of-place. Go interfaces — unlike, say, Java interfaces — generally belong with the API that consumes the interface, not the API that provides implementations of that interface.
For more on that principle, see:
https://golang.org/wiki/CodeReviewComments#interfaces
https://hyeomans.com/golang-and-interfaces-misuse/
https://dave.cheney.net/2016/08/20/solid-go-design
https://dave.cheney.net/practical-go/presentations/gophercon-israel.html#_prefer_single_method_interfaces
You can use a type alias.
type IRes = resources.IResource
In contrast to a type definition, an alias is just another name for the same type and not a new distinct type. A type definition would be without the =.

In Go, is it convention to capitalize type names?

In most Go programs I have seen, even those that have just one package, the names of types are written with a capital letter, which makes them exported.
Is this just a convention to make clear that they are types or is there a need for all types to be exported?
Initially I was going to put examples here of exported types, but looking around some popular Go projects I only found exported types so far. So any example of an unexported type in a reasonably large Go project would be welcome.
The type starting with an uppercase letter are exported to other packages. Those starting with a lowercase letter can be used only inside the package. Important note: it is possible to export an interface without exporting the struct that implements it.
It is not a convention to export types. Only export them if you allow them to be used outside the package. In the example you provided, there was no need to export the Server type, because it has no exported field or methods.
Export only the types that are part of the contract with the client. Exporting types that are only used internally is a mistake and is confusing in the documentation.
Edit:
A little clarification about the Server type. It implements the http.Handler interface (must define ServeHTTP(http.ResponseWriter, *http.Request) ), so it is possible to make it not exported and use the interface as the return type of NewServer function.
Types can be private.
Having a public function returning a private type however does not work. As long as the type is only used package internally, I keep it private.
EDIT:
In your example, Server has to be public because it is returned by public functions and thus used outside the package. The function NewServer returns *Server.
EDIT for new example:
In the new example this is the main package. It can't be imported anyway.
It's not a matter of convention, Go actually uses capitalization to determine which things are exported, i.e. available when you import the package.
E.g. if I have:
package a
const Exported = "hi"
const nonExported = "mom"
Then in a different package, you can import a.Exported but not a.nonExported:
package main
import "PATH/a"
func main() {
println(a.Exported)
// this won't compile
// println(a.nonExported)
}

How to define a struct globally and reuse it packages

Im very new to Go and have this "design" problem.
I have a main program passing jobs through channels. Each job will end up in a function defined in separate "worker" packages. Jobs are structs.
Now i want each function called, to return result as a common struct through a "result" channel. But the package doesnt know about the struct definition i have in main and so i cannot define it.
package main
type resultEvent struct {
name string
desc string
}
Then in a worker package:
package worker
func Test() {
result := &resultEvent{name: "test"}
}
Of course the idea is to eventually send this result down a channel, but even this simple example wont work, because worker doesnt know about resultEvent.
What would be the correct way of doing this?
Update:
It should be noted that there will be many worker packages, doing different things. Sorta like "plugins" (only not pluggable at all).
I dont want to define a redundant struct in each go-file and then have to maintain that over maybe 50 very different worker-packages.
Im looking for what would be the correct way to structure this, so i can reuse one struct for all worker-packages.
Basically, anything that lives in package main will only ever be able to be referenced from that pacakge. If you want it to be shared between multiple packages, put it in the worker package and export it (Upper case the first letter), then import worker from main.
No matter what, you will have to import the package which contains the type you'd like to use. However, the reason this isn't working for you is because your type is not exported. You need to uppercase the types name like;
type ResultEvent struct {
name string
desc string
}
Worth checking out what exported vs unexported means but basically upper case means exported which is similar to the public specifier in other systems languages. Lower case means unexported which is more like internal or private.
As pointed out in the comment and other answer you can't import main so I believe you'll have to move your types definition as well.
One possible way would be something like:
package workerlib
type ResultEvent struct {
Name string // Export the struct fields, unless you have a
Description string // real good reason not to.
}
Then stick the rest of the worker utility functions in that package. Unless you provide suitable methods to read the name and description from an event, simply export the fields. If you have an absolute need to make them changeable only from within the package they're defined in, you could keep them unexported, then provide a function to create a ResultEvent as well as methods to read the name and description.

Resources