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
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.
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.
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.
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
}
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
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
Related
I have the following function:
override fun countForTicket(dbc: SQLiteDatabase, ticketId: Long): Int {
var ret: Int
dbc.query(
TABLE_SECOND_CHANCE_PRIZES, arrayOf("count(id)"),
"ticket = ?", arrayOf(ticketId.toString()),
null, null, null
).use { c ->
ret = if (c.moveToFirst()) {
c.getInt(0)
} else {
0
}
}
return ret
}
The problem is that in line return ret ret is underlined with red and when trying to compile it gives me error:
Variable 'ret' must be initialized
From my point of view it seems that ret is always initialized. What am I missing?
Is it because the initialization is happening in a lambda and the compiler cannot guarantee that the variable is initialized?
The compiler isn't smart enough to know for sure the lambda will be run once, so it can't figure this out for you.
The reason we don't have this problem with many of the standard library higher-order functions is that they utilize contracts, which tell the compiler what they are doing with the lambda that is passed in (such as guaranteeing that the lambda will be called exactly once).
Unfortunately, Closeable.use() doesn't specify a contract (possibly because of it re-throwing exceptions?).
But use does return the result of calling the lambda, so you could do
val ret = dbc.query(...).use { c ->
if (c.moveToFirst()) {
c.getInt(0)
} else {
0
}
}
The compiler don't allow unsafe variables like that to be returned. A variable must always be something.
In your case, ret is initialized inside a lambda. The compiler doesn't know if this lambda is executed or not. If not, ret remains in its unsafe state. Throwing a NullPointerException at the end.
If you're sure that this variable is always assigned you can look at lateinit variables. You can also put a default value to it var ret = 0 and ommit the else statement.
I'm just starting with Golang and I am very confused about interacting with other packages and using structs. Right now I am simply trying to return the a struct generated by a method in the gopsutil library. Specifically the return of the following function: enter link description here
My code for this is the following:
package main
import (
"fmt"
"github.com/shirou/gopsutil/cpu"
)
func main() {
cpu_times = getCpuTime()
fmt.Println(cpu_times)
}
func getCpuTime() TimesStat {
ct, _ := cpu.Times(false)
return ct
}
This returns TimesStat as undefined. I tried returning a few different syntactical variations, however the only return value I have found that compiles is interface{}, which gets me the struct inside of brackets (eg [{values...}]) and that led to some other problems. I can't seem to find any examples of what I am trying to do. Any help appreciated thanks.
you need to include the package name before the type, like so:
func getCpuTime() []cpu.TimesStat { // with package name before type
ct, _ := cpu.Times(false)
return ct
}
since that is a slice of cpu.TimesStat, you probably want to add an index in the calling function or change the function to just return a single cpu.TimesStat. (thanks to #algrebre)
I am developing some tests for my code (using the testing package), and I am wondering what's the best way to mock functions inside the tested function:
Should I pass the function as parameter?
In that case, what if that function calls another function? Should I pass both the first and second function as parameters in the tested one?
Note: some of the functions are called on objects (i.e. someObj.Create()) and use HTTP API calls.
UPDATE for clarification:
Example: functions
func f1() error {
... //some API call
}
func (s *SomeStruct) f2() error {
return f1
}
func f3() error {
return nil
}
func f4() error {
...
err = obj.f2()
...
err = f3()
...
}
For the above: if I want to test f4, what's the best way to mock f2 and f3?
If I pass f2 and f3 to f4 as parameters it would work, but then what for the f2 test? Should I pass f1 to f2 as parameter?
And if that's it, should then f4 have f1 as well in the parameters?
As a general guideline, functions aren't very mockable so its in our best interests to mock structs that implement a certain interface that may be passed into functions to test the different branches of code. See below for a basic example.
package a
type DoSomethingInterface interface {
DoSomething() error
}
func DoSomething(a DoSomethingInterface) {
if err := a.DoSomething(); err != nil {
fmt.Println("error occurred")
return
}
fmt.Println("no error occurred")
return
}
package a_test
import (
"testing"
"<path to a>/a"
)
type simpleMock struct {
err error
}
func (m *simpleMock) DoSomething() error {
return m.err
}
func TestDoSomething(t *testing.T) {
errorMock := &simpleMock{errors.New("some error")}
a.DoSomething(errorMock)
// test that "an error occurred" is logged
regularMock := &simpleMock{}
a.DoSomething(regularMock)
// test "no error occurred" is logged
}
In the above example, you would test the DoSomething function and the branches that happens eg. you would create an instance of the mock with an error for one test case and create another instance of the mock without the error to test the other case. The respective cases are to test a certain string has been logged to standard out; in this case it would be "error occurred" when simpleMock is instantiated with an error and "no error occurred" when there simpleMock is not instantiated with an error.
This can of course be expanded to other cases eg. the DoSomething function actually returns some kind of value and you want to make an assertion on the value.
Edit:
I updated the code with the concern that the interface lives in another package. Note that the new updated code has a package a that contains the interface and the function under test and a package a_test that is merely a template of how to approach testing a.DoSomething.
I'm not sure what you're trying to do here but I'll explain how testing should be done in Go.
Lets say we have an application with the following directory hierarchy:
root/
pack1/
pack1.go
pack1_test.go
pack2/
pack2.go
pack2_test.go
main.go
main_test.go
We'll assume that pack2.go has the functions you want to test:
package pack2
func f1() error {
... //some API call
}
func (s *SomeStruct) f2() error {
return f1
}
func f3() error {
return nil
}
func f4() error {
...
err = obj.f2()
...
err = f3()
...
}
Looks good so far. Now if you want to test the functions in pack2, you would create a file called pack2_test.go. All test files in go are named similarly (packagename_test.go). Now lets see the inside of a typical test for a package (pack2_test.go in this example):
package pack2
import (
"testing"
"fmt"
)
TestF1(*testing.T) {
x := "something for testing"
f1() // This tests f1 from the package "pact2.go"
}
TestF2(*testing.T) {
y := new(somestruct)
y.f2() // tests f2 from package "pact2.go"
}
TestF3(*testing.T) {
/// some code
f3() // tests f3
}
TestF4(*testing.T) {
/// code
f3() // you get the gist
}
Let me explain. Notice how in pack2_test.go, the first line says that the package is pack2. In a nutshell, this means that we're in the "scope" of the package pack2 and thus all the functions found in pack2 can be called as if you're within pack2. Thats why, within the Testf* functions, we could've called the functions from pack2. Another thing to note is the imported package "testing". This helps with two things:
First, it provides some functionality for running tests. I won't go into that.
Second, it helps identify the functions that go test should run.
Now to the functions. Any function within a test package that has the prefix "Test" and the parameters "t *testing.T" (you can use "*testing.T" when you don't need to use the testing functionality) will be executed when you run go test. You use the variable t to reference the testing functionality I mentioned. You can also declare functions without the prefix and call them within the prefixed functions.
So, if I go to my terminal and run go test, it will execute the functions you want to test, specified in pack2_test.go
You can learn more about testing here and here
I want to parse and set a variable conditionally in Go at the global package level based on the value of of an ENV var, so that I don't have to check for it every time in a utility function (as the variable would be declared once at run time). For example, what I want to accomplish is (Go pseudo-code):
import (
"fmt"
"os"
"strconv"
)
// This works to read the value of MYVAR (=true/false)
var myvar string = os.Getenv("MYVAR")
// Apparently this is too much for Go
var myvarbool, _ = strconv.ParseBool(myvar)
// Utility function to check for value
func mycheck() {
if myvarbool {
fmt.Print("MYVAR is true")
}
}
This is a library package, so doesn't have a main() function to do this kind of setup, but I want to be able to use mycheck() in other functions in the library, and don't want to have to read and parse MYVAR every time mycheck() is called.
One way to accomplish what you're looking to do would be to process the environment variable in an init() function, so something like the following would work:
package main
import (
"fmt"
"os"
"strconv"
)
var (
myvar string = os.Getenv("MYVAR")
myvarbool bool
)
func init() {
myvarbool, _ = strconv.ParseBool(myvar)
}
// Utility function to check for value
func mycheck() {
if myvarbool {
fmt.Print("MYVAR is true")
}
}
Playground
I'm not sure what problem you had, your code from the OP is valid, also you can have it in one line like:
var myvarbool, _ = strconv.ParseBool(os.Getenv("MYVAR"))
playground
After actually thinking about this for a couple of minutes, I've realised I can just create a wrapper function to do the work, and call that instead (again, largely pseudo-code without extra checks):
var myenvbool bool = myenv("MYVAR")
func myenv(envvar string) bool {
myenvvalue := os.Getenv(envvar)
myenvbool, _ := strconv.ParseBool(myenvvalue)
return myenvbool
}
func checkenv() {
if myenvbool {
fmt.Print("myenvbool is true")
}
}
How would I go about having a package register some object (for instance a function) to a registry at load time such that adding a new package to the program will automatically add new functionality to the program without having to modify code in other packages?
Here's a code sample which should illustrate what I'm trying to do.
src/say/say.go:
package main
import (
"os"
"reg"
)
func main() {
if len(os.Args) != 2 {
os.Stderr.WriteString("usage:\n say <what_to_say>\n")
os.Exit(1)
}
cmd, ok := reg.GetFunc(os.Args[1])
if ok {
os.Stdout.WriteString(cmd())
os.Stdout.Write([]byte{'\n'})
} else {
os.Stderr.WriteString("I can't say that!\n")
os.Exit(1)
}
}
src/reg/reg.go:
package reg
var registry = make(map[string]func() string)
func Register(name string, f func() string) {
registry[name] = f
}
func GetFunc(name string) (func() string, bool) {
f, ok := registry[name]
return f, ok
}
src/hi/hi.go:
package hi
import (
"reg"
}
func init() {
reg.Register("hi", func() string {
return "Hello there!"
})
}
When coding this up, I naively supposed that perhaps the package "hi" would be found by the go compiler and compiled into the binary. Then, at load time, the init() function would run. If that was how things worked, I'd have been able to drop in something like the following to add a new "say no" command:
src/no/no.go:
package no
import (
"reg"
)
func init() {
reg.Register("no", func() string {
return "Not a chance, bub."
})
}
But, it doesn't seem to work that way.
I may just be thinking about the problem too much through a Pythonic lens, but is there some way to accomplish something somewhat like what I'm shooting for? If not, I'll change my tack and I will have learned something new about the Go way of doing things.
Thanks in advance!
Since you must use import in order for the compiler add a package, my suggestion would be to do the following:
Instead of using multiple drop-in packages, you could have only one single package with multiple drop-in files. Each command file is placed in the same package folder (cmds). This is possible since you are allowed to have multiple init in a package, and you would not have to make any edits to say.go, no matter how many new drop-in files you add.
package main
import (
"os"
"reg"
_ "cmds"
)
....
And previous package no
// Command no
package cmds
import (
"reg"
)
func init() {
reg.Register("no", func() string {
return "Not a chance, bub."
})
}
Based on what I read about the init function, I think your example would work if you just added "hi" and "no" to the list of packages you are importing in say.go. Does it work if you do that?
I know you did not want to change the code in say.go, so I suppose that isn't really a solution.