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.
Related
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
I know, similar questions have been asked, but I found no answer for that case:
type ExportedStruct struct{ //comes from a dependency, so I can't change it
unexportedResource ExportedType
}
I want to call an exported method Close() on unexportedResource.
What I did was:
rs := reflect.ValueOf(myExportedStructPtr).Elem() //myExportedStructPtr is a pointer to an ExportedStruct object
resourceField := rs.FieldByName("unexportedResource")
closeMethod := resourceField.MethodByName("Close")
closeMethod.Call([]reflect.Value{reflect.ValueOf(context.Background())})
, which results in reflect.flag.mustBeExported using value obtained using unexported field.
This is quite annoying since I want to run more than one test which utilizes ExportedStruct, but I can't as long as the underlying resource is not used.
Since I can access private fields (as explained here) I have a bit hope that I'm allowed to access the public method of that field somehow, too. Maybe I'm just reflecting wrong?
Unexported fields are for the declaring package only. Stop messing with them. They are not for you.
The linked answer can only access it by using package unsafe, which is not for everyday use. Package unsafe should come with a "not to touch" manual.
If you do need to access unexportedResource, make it exported. Either the field, or add a method to the type that calls unexportedResource.Close(). Or add a utility function to the package that does this (functions in the same package can access unexported fields and identifiers).
While #icza's answer gives you reason why you should not do it, here is a way of how to do it using reflect and unsafe:
var t pkg.T
v := reflect.ValueOf(&t).Elem()
f := v.FieldByName("t")
rf := reflect.NewAt(f.Type(), unsafe.Pointer(f.UnsafeAddr())).Elem()
rf.MethodByName("Print").Call(nil)
playground: https://play.golang.org/p/CmG9e4Bl9gg
I am afraid that what you are trying to do is impossible through reflection.
Below is the implementation of reflect.Call:
func (v Value) Call(in []Value) []Value {
v.mustBe(Func)
v.mustBeExported()
return v.call("Call", in)
}
As you can see there is an explicit check (i.e. mustBeExported()) if Value was obtained from an exported field or not.
Typically there is a reason why fields are not exported. If you want to manipulate that field you will have to use methods implemented by the ExportedStruct struct.
If you can modify the code where ExportedStruct is defined, you can easily implement a wrapper Close method on that. For example:
type ExportedStruct struct{
unexportedResource ExportedType
}
func (e ExportedStruct) Close(){
e.unexportedResource.Close()
}
Say I have these two files in golang:
// main/a/a.go
import "main/b"
type Model struct {
ID int `json:"id"`
Me int `json:"me"`
You int `json:"you"`
}
func zoom(v b.Injection){
}
func Start(){
// ...
}
and then the second file looks like:
// main/b/b.go
import "main/a"
type Injection struct {
ModelA a.Model
}
func GetInjection() Injection {
return Injection{
ModelA: a.Start(),
}
}
so as you can see, these are circular imports, each file imports the other.
So I need to use a 3rd file, and have these two files import the 3rd file.
But I am really struggling how to get this functionality and avoid cyclic imports.
My first step, is to move the Injection type into a 3rd file:
// main/c/c.go
type Injection struct {
ModelA interface{} // formerly a.Model
}
so now this is what it looks like:
a imports c
b imports a,c
so no more cycles, however the problem is that I don't know how to create an interface for a.Model in c.go? An empty interface{} like I used above doesn't work, for the normal reasons.
How do I solve this cyclic import problem with these 2 original files?
If you want them to put into separate packages, you can't have Model and zoom() in the same package, as zoom() refers to Injection and Injection refers to Model.
So a possible solution is to put Model into package a, zoom() into package b, and Injection into package c. c.Injection can refer to a.Model, b.zoom() can refer to c.Injection. There's no circle in this:
b.zoom() --------> c.Injection ---------> a.Model
I assume there are other references in your real code which are not in the question which may prevent this from working, but you can move "stuff" around between packages, or you can break it down into more.
Also, if things are coupled this "tight", you should really consider putting them into the same package, and then there is no problem to solve.
Another way to solve circular import issue is to introduce interfaces. E.g. if your zoom() function would not refer to Injection, the package containing Model and zoom() would not need to refer to Injection's package.
Inspect what zoom() needs to do with Injection. If that is method calls, that's already good. If not, add methods to Injection. Then you may define an interface in zoom()'s package containing the methods zoom() needs to call, and change its parameter type to this interface. Implementing interfaces in Go is implicit, there is no declaration of intent. So you can remove the reference in the parameter type, still you will be able to pass Injection values to zoom().
Also related, check Dave Cheney's thoughts about organizing code:
I believe code should be organised into packages names for what the package provides, not what it contains. This can sometimes be subtle, but usually not.
For example, http, provides http clients and servers.
As a counter example, package utils is a poor name, yes it provides utilities, but you have no idea what from the name, in truth this package is named for what it contains.
If your project is a library, it should contain one package (excluding examples and possibly utility commands), if it contains more packages, that is a sign that the library is trying to do too many things.
Prefer to avoid multiple packages by default, only split code by package if there is a clear separation of concerns. In my experience many frustrations with complex and possibly circular package structures are the result of too many packages in a project.
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)
}
Why do some packages declare two equal functions the only difference is one is exported and the other is not but the one that is exported just returns the non-exported function like this:
func Foo() {
return foo()
}
func foo() {
log.Println("Hello")
}
Why not just move the log into the exported function and get rid of the extra line? Obviously there is a reason but I don't really see one if you can just use the exported one everywhere. Thanks!
Example here of it being used in Production
You mentioned a couple examples. The first example (https://github.com/yohcop/openid-go/blob/master/verify.go#L11-L13):
func Verify(uri string, cache DiscoveryCache, nonceStore NonceStore) (id string, err error) {
return verify(uri, cache, urlGetter, nonceStore)
}
You can see that the unexported verify function takes an extra urlGetter argument. This may be something that a client of this package cannot or should not provide. The exported function determines how clients of the package can/should use it; the signature of the non-exported function reflects the dependencies required to do whatever business logic verify is doing.
The second example(https://github.com/golang/oauth2/blob/master/oauth2.go#L259-L266):
func StaticTokenSource(t *Token) TokenSource {
return staticTokenSource{t}
}
// staticTokenSource is a TokenSource that always returns the same Token.
type staticTokenSource struct {
t *Token
}
This restricts how clients can construct the staticTokenSource: there is only one way to do it, via the StaticTokenSource constructor, and it cannot be done directly via a struct literal. This can be useful for many reasons, e.g. input validation. In this case, you want the safety of knowing that the client cannot mutate the t field on the object, and in order to do this, you leave the t field unexported. But when it's unexported, the client will not be able to construct the struct literal directly, so you must provide a constructor.
In general, it makes your code much easier to reason about when you can restrict how things are accessed, constructed, or mutated. Golang packages give you a nice mechanism to encapsulate modules of business logic. It's a good idea to think about the conceptual components of your software, and what their interfaces should be. What really needs to be exposed to client code consuming a given component? Only things that really need to be exported should be.
Further reading: Organizing Go code