Is it possible to reuse constant names in different file scopes? - go

Is it possible to have two constants with the same name in different files?
foo.go
const {
deviceId = 1 // I dont need this outside the file scope
}
type DeviceA struct {
.. some fields..
// I cannot make constant fields here
}
.. some methods ...
bar.go
const {
deviceId = 2 // I dont need this outside the file scope
}
type DeviceB struct {
.. some fields ..
// I cannot make constant fields here
}
.. some methods ...
If I do this, I get that deviceId has been redeclared. How can I keep these constants in the scope of the file?
I would not mind using some kind of namespace for the constants if that were a solution to this.

The Go Programming Language Specification
Packages
Go programs are constructed by linking together packages. A package in
turn is constructed from one or more source files that together
declare constants, types, variables and functions belonging to the
package and which are accessible in all files of the same package.
Those elements may be exported and used in another package.
Source file organization
Each source file consists of a package clause defining the package to
which it belongs, followed by a possibly empty set of import
declarations that declare packages whose contents it wishes to use,
followed by a possibly empty set of declarations of functions, types,
variables, and constants.
[constants] belonging to the package are accessible in all files of the same package.
The fundamental Go compilation unit is the package. The source files in the package are merged to form the input to the compiler.

To answer your question: It is not possible to have two constants with the same name, in the same scope, the same package in separated files.
There is no namespace or file scope in Go.
However, it is possible to have two constants of the same name in the same package but declared at different scope:
package main
import (
"fmt"
)
const a = 1
func main() {
const a = 2
fmt.Println(a) // output is 2
}
For details of scope, please see: https://golang.org/ref/spec#Declarations_and_scope

Related

How to import/use other struct in the same package but different folder

I have folder structure like this:
> validations
> user
> user.validation.go
> address
> address.validation.go
the package name for those two file is validations
inside user.validation.go I try to use the address validation struct like this:
type UserValidation struct {
Address AddressValidation // the error says: undeclared name: AddressValidation
}
and I have tried calling package name before struct like this:
type UserValidation struct {
Address validations.AddressValidation // the error says: undeclared name: validations
}
and I have tried to import it first:
import "example/go-api/validations"
and the error says: AddressValidation not declared by package validations
You have three separate packages in each of these folders:
validations
user
address
The validations folder contains only other packages so is not able to be usefully imported; it contains no code with any exports.
The user folder also contains a package named validations this can usefully imported to access the exported UserValidation type.
The address folder also contains a package named validations this can be usefully imported to access the exported AddressValidation type.
But GoLang does not treat these as all forming a single validations package. A 'package' is a namespace, but packages with the same name are not the same namespace. They all remain separate and distinct packages (and namespaces).
If the validations package in the user folder wishes to import the validations package in the address folder it can do so but must reference the full path to that package and must alias the import since the folder name does not match the name of the package it contains:
import validations "example/go-api/validations/address"
type UserValidation struct {
Address validations.AddressValidation
}
will work just fine.
But note that since this involves an alias, that alias can be anything you like - it doesn't have to match the name of the imported package. i.e. this is just as valid:
import v "example/go-api/validations/address"
type UserValidation struct {
Address v.AddressValidation
}
If some other package in your project wishes to reference both UserValidation and AddressValidation it must import both of the separate validations packages that contain them and provide unique aliases for each:
import (
addressValidations "example/go-api/validations/address"
userValidations "example/go-api/validations/user"
)
and may then do something like:
var (
av addressValidations.AddressValidation
uv userValidations.UserValidation
)
The key to all of this is that folders are not a way of organising files within a package. A folder is a package.
Unless you have a specific reason for doing otherwise it is best to:
Name a package for the folder that contains its files
Use unique names for packages (in the same project/module)
There are occasional, valid exceptions to rule #2, e.g. where a package name makes sense in two different and mutually exclusive contexts. i.e. where no other package would never wish or need to import different packages of the same name from those different contexts.
I've yet to encounter a valid exception to rule #1. :)
Possible Alternative Approach
If you really want to keep UserValidation and AddressValidation in separate packages, you could name the packages user and address (i.e. apply rule #1: name each package for their respective folders).
Then, since the package name provides the address or user context for the symbols within them, you can rename the types to simply Validation in each case.
Your user.go code then becomes:
package user
import "example/go-api/validations/address"
type Validation struct {
Address address.Validation
}
and your address.go code:
package address
type Validation struct {}
and variables in a package that imports both user and address validations become:
import (
"example/go-api/validations/address"
"example/go-api/validations/user"
)
var (
av address.Validation
uv user.Validation
)
Caveat Coder
This is not a prescription! Without knowing more about your specific use case I have no idea whether this is the best way to skin this particular feline; it is merely an illustration of one way.
In short: use your folder/package names to help add context and meaning to the symbols exported by your packages.

How to access unexported package private variable

Code like below
package internal
var internalVar = "foobar"
How can i access this internalVar from another package like package main?
internal package is placed in a 3rd party library, and my application needs to use some private info which original author is not willing to expose as a public API.
As #mkopriva mentioned, internal variables should not be accessed outside their packages at all. Go explicitly does that as a way to enforce accessibility and if the internal var is not exported, then it shouldn't be accessed. Again: don't do this, it's bad Go and we don't like it. Always export your variables when you need to access them outside your packages.
That huge disclaimer above being said, there are ways on how you can access internal variables: pointers, assembly and linkname. I'll explain the later since it's the easiest one:
Go compiler has this nifty directive called //go:linkname. It basically links variables/functions between different packages. From the documentation:
//go:linkname localname [importpath.name]
This special directive does not apply to the Go code that follows it. Instead, the //go:linkname directive instructs the compiler to use “importpath.name” as the object file symbol name for the variable or function declared as “localname” in the source code. If the “importpath.name” argument is omitted, the directive uses the symbol's default object file symbol name and only has the effect of making the symbol accessible to other packages. Because this directive can subvert the type system and package modularity, it is only enabled in files that have imported "unsafe".
That means that you can use it to access otherwise unexported functions and variables, with something like this:
main.go
package main
import (
"temp/test-access-internal/internal"
_ "unsafe"
)
//go:linkname message temp/test-access-internal/internal.message
var message string
func main() {
message = "abc"
println(message)
internal.SayHello()
}
internal/internal.go
package internal
var message string = "Hello!"
func SayHello() {
println(message)
}
You will see that the output respects the "abc" value we've overwritten.
Don't do this unless you really, really needs to monkey patch something.

Error: Type is redeclared in this package

In req.go, I have:
package basic
type Headers struct {
}
type Body struct {
}
and in res.go, I have the same:
package basic
type Headers struct {
}
type Body struct {
}
and so I get this error:
'Headers' redeclared in this package
'Body' redeclared in this package
Is the only way to solve this is to put req and res in their own folders? Ughh so many folders.
Packages are the basic unit of creating separated and reusable code. From inside the package, you refer to its identifiers (identifiers declared in the package) by their name. From the "outside" (from other packages), you import the package and you refer to its identifiers using a qualified identifier, which is
QualifiedIdent = PackageName "." identifier .
When a package consists of multiple files, each identifier declared in any of the package's files will belong to the package block. Quoting from Spec: Declarations and scope:
The scope of an identifier denoting a constant, type, variable, or function (but not method) declared at top level (outside any function) is the package block.
What this means is that you can't have the same identifier declared in 2 files of the same package.
If you think about it, this is how it should be. What happens if someone from the outside writes basic.Header? Which Header should that mean?
One option is to put them into 2 separate packages: req and resp, then you can refer to them as req.Header and resp.Header, and you know exactly what they mean just by looking at these qualified identifiers.
If you don't want 2 packages, simply rename them. Give them meaningful names, such as ReqHeader and RespHeader, and then you may refer to them like basic.ReqHeader and basic.RespHeader.

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