Non-declaration statement outside function body in Go
VariablesScopeGoPackageGlobalVariables Problem Overview
I'm building a Go library for an API that offers JSON or XML formatted data.
This API requires me to request a session_id
every 15 minutes or so, and use that in calls. For example:
foo.com/api/[my-application-id]/getuserprofilejson/[username]/[session-id]
foo.com/api/[my-application-id]/getuserprofilexml/[username]/[session-id]
In my Go library, I'm trying to create a variable outside of the main()
func and intend to ping it for a value for every API call. If that value is nil or empty, request a new session id and so on.
package apitest
import (
"fmt"
)
test := "This is a test."
func main() {
fmt.Println(test)
test = "Another value"
fmt.Println(test)
}
What is the idiomatic Go way to declare a globally-accessible variable, but not necesarilly a constant?
My test
variable needs to:
- Be accessible from anywhere within it's own package.
- Be changeable
Variables Solutions
Solution 1 - Variables
You need
var test = "This is a test"
:=
only works in functions and the lower case 't' is so that it is only visible to the package (unexported).
A more thorough explanation
test1.go
package main
import "fmt"
// the variable takes the type of the initializer
var test = "testing"
// you could do:
// var test string = "testing"
// but that is not idiomatic GO
// Both types of instantiation shown above are supported in
// and outside of functions and function receivers
func main() {
// Inside a function you can declare the type and then assign the value
var newVal string
newVal = "Something Else"
// just infer the type
str := "Type can be inferred"
// To change the value of package level variables
fmt.Println(test)
changeTest(newVal)
fmt.Println(test)
changeTest(str)
fmt.Println(test)
}
test2.go
package main
func changeTest(newTest string) {
test = newTest
}
output
testing
Something Else
Type can be inferred
Alternatively, for more complex package initializations or to set up whatever state is required by the package GO provides an init function.
package main
import (
"fmt"
)
var test map[string]int
func init() {
test = make(map[string]int)
test["foo"] = 0
test["bar"] = 1
}
func main() {
fmt.Println(test) // prints map[foo:0 bar:1]
}
Init will be called before main is run.
Solution 2 - Variables
If you accidentally use "Func" or "function" or "Function" instead of "func" you will also get:
> non-declaration statement outside of function body
Posting this because I initially ended up here on my search to figure out what was wrong.
Solution 3 - Variables
We can declare variables as below:
package main
import (
"fmt"
"time"
)
var test = "testing"
var currtime = "15:04:05"
var date = "02/01/2006"
func main() {
t := time.Now()
date := t.Format("02/01/2006")
currtime := t.Format("15:04:05")
fmt.Println(test) //Output: testing
fmt.Println(currtime)//Output: 16:44:53
fmt.Println(date) // Output: 29/08/2018
}
Solution 4 - Variables
> Outside a function, every statement begins with a keyword (var
, func
, and so on) and so the :=
construct is not available.
You can read more information here: https://tour.golang.org/basics/10
Solution 5 - Variables
Short variable declarations i.e. :=
, can ONLY be used within functions.
e.g.
func main() {
test := "this is a test"
// or
age := 35
}
Declarations outside a function you must make use of keywords like var, func, const
e.t.c depending on what you want (in this case we're using var
).
Declaring a variable outside a function makes it accessible within its package.
package apitest
import (
"fmt"
)
// note the value can be changed
var test string = "this is a test"
func main() {
fmt.Println(test)
test = "Another value"
fmt.Println(test)
}
Extra info
If you want the variable to be accessible both within and outside its package, the variable has to be capitalized e.g.
var Test string = "this is a test"
this will make it accessible from any package.
Solution 6 - Variables
I got this error when I was trying to run Go app with function definition like this:
(u *UserService) func GetAllUsers() (string, error) {...} //Error code
The correct way of defining a function (receiver function) was:
func (u *UserService) GetAllUsers() (string, error) {...} //Working code