Is it possible to declare a map at package level in golang? - go

I want a make global map. I am trying the following
package main
import "fmt"
globalMap := make(map[string]string)
func main() {
globalMap["a"] = "A"
fmt.Println(globalMap)
}
It gives me following compilation error on line globalMap := make(map[string]string):
expected declaration, found 'IDENT' mas
non-declaration statement outside function body
Looking at the error i understand it won't allow me to create a global map. what could the best way to create a global map ?
Thanks.

You can’t use the := syntax outside a function body, but you can use the normal variable declaration syntax:
var globalMap = make(map[string]string)

Related

How to declare to variables of different datatypes in a single statement in Go [duplicate]

This question already has answers here:
Multiple variables of different types in one line in Go (without short variable declaration syntax)
(2 answers)
Closed 1 year ago.
I want to declare two variables of different datatypes(string and error) in a single statement in Go. I do not want to use the short declaration(:=) operator because I like specifying the type of the variable at declaration.
I am following a Go tutorial from the Go docs. I have a function called greetings.Hello() that I am calling from another module. The greetings.Hello() function looks like this:
package greetings
import (
"errors"
"fmt"
)
func Hello(name string) (string, error) {
// If no name was given, return an error with a message
if name == "" {
return "", errors.New("empty name")
}
// If a name was received, return a value
var message string = fmt.Sprintf("Welcome %v!", name)
return message, nil
}
So as you can see, this function returns two values(a string and an error). So ultimately, I would have to assign the result of this function to two variables in the caller. I am calling the greetings.Hello() function from a module named hello. The main function of the hello module's main package looks like this:
package main
import (
"fmt"
"log"
"creating_modules/greetings"
)
func main() {
log.SetPrefix("greetings: ")
log.SetFlags(0)
var message string, err error = greetings.Hello("")
if err !=nil {
log.Fatal(err)
}
fmt.Println(message)
}
The creating_modules/greetings is the greetings module that contains the function Hello(). Most of the gophers tackle it like this:
message, error := greetings.Hello()
But I want to declare the variables along with their datatypes in a single statement. Also the two variables should be assigned the return values of greetings.Hello(). The above mentioned main function of the hello module returns an error when it is run because of the incorrect assignment, referring to this line:
var message string, err error = greetings.Hello("")
The Go compiler returns this error when this code is run using go run:
.\hello.go:14:20: syntax error: unexpected comma at end of statement
This issue can simply be reproduced by copy-pasting the code above(note that the greetings module is a local module so you will need to set the reference path for go tools using go edit -replace)
Another thing to be noted is that my question is different from this question because that question is about declaring variables with the same data type in a single statement whereas mine is about declaring multiple variables with different data types in a single statement.
P.S i won't be surprised to know that Golang does not have this feature
declare the variables along with their datatypes in a single statement
Not possible
Supporting clause from the language spec under Variable declarations
If a type is present, each variable is given that type. Otherwise, each variable is given the type of the corresponding initialization value in the assignment. If that value is an untyped constant, it is first implicitly converted to its default type;
So something like below could work by not specifying either of the types, but you could very well use short variable declarations using := instead
var message, error = greetings.Hello()
But you can declare the variables explicitly with their type information and use the = assignment.
var message string
var err error
if message, err = greetings.Hello(""); err != nil {
log.Fatal(err)
}

How to resolve "use of package without a selector error"

I am using a package: ccs08
In my main, I am importing the package and using some of its functions. I have followed the usage from the unit tests given:
package main
import(
"fmt"
"math/big"
"crypto/rand"
"zkrp/ccs08"
"zkrp/crypto/bn256"
)
func main(){
var (
r *big.Int
s []int64
)
s = make([]int64, 4)
s[0] = 12
s[1] = 42
s[2] = 61
s[3] = 71
p, _ := ccs08.SetupSet(s)
r, _ = rand.Int(rand.Reader, bn256.Order)
proof_out, _ := ccs08.ProveSet(12, r, p)
result, _ := ccs08.VerifySet(&proof_out, &p)
if result != true {
fmt.Println("not verified")
}
}
I then have a similar main file,main2, where I am using another set of functions from the same package. This does NOT work
package main
import(
"fmt"
"math/big"
"crypto/rand"
"zkrp/ccs08"
"zkrp/crypto/bn256"
)
func main(){
var (
result bool
zkrp ccs08
)
zkrp.Setup(347184000, 599644800)
zkrp.x = new(big.Int).SetInt64(419835123)
zkrp.r, _ = rand.Int(rand.Reader, bn256.Order)
e := zkrp.Prove()
result, _ = zkrp.Verify()
if result != true {
fmt.println("not verified")
}
}
I am getting this error:
./main2.go:7: imported and not used: "zkrp/ccs08".
./main2.go:16: use of package ccs08 without selector.
What am I doing wrong?
For the first file, everything works because the code is using public members of the ccs08 package. However, this is not the case for the second file.
You mentioned the code in the second file is copied from here.
To understand why the code does not work when pasted into a main method outside the ccs08 package, you need to understand what it is doing in its original location. Specifically this part:
var (
result bool
zkrp ccs08
)
In the original location (inside the ccs08 package) there is a private struct type named ccs08. The declaration can be seen here. What the above code is doing is creating a variable named zkrp the type of which is the private struct type ccs08. Then, the various functions called on the variable are methods bound to this private struct (you can see the methods here).
Now, in the code you posted (after pasting into a location outside the ccs08 package), there is no way to access the private ccs08 struct (I can't even find a public method which returns it in the zkrp source code). So, what Go sees when it tries to execute this code is a typo (where it thinks you are trying to write something of the form package.Member):
// this looks like you wanted to declare a variable with type:
// "ccs08.SomeType" but forgot to write ".SomeType"
// Thus Go gives the error: "use of package ccs08 without selector"
var zkrp ccs08
And the "imported and not used" error is because the ccs08 package isn't used in a valid way anywhere in the code.
The code which you copied is honestly pretty confusing with all the reusing of the strings ccs08 and zkrp for naming of different things. I hope this clears it up a bit.

Viper, cannot get the value initialized outside the functions

I have a problem using a viper, I have assigned variable by viper method, so when I try to get value inside any function I have a null value. Does anybody have any idea why does it happen so? Any other variables initialization works fine, but not viper GetString method.
Structure:
main.go
package main
import (
"project/Model"
"github.com/spf13/viper"
...
)
func main() {
//Config handling
viper.SetConfigName("main")
viper.AddConfigPath("/config/")
err = viper.ReadInConfig()
...
}
Package Model
package Model
import ("github.com/spf13/viper"
...
)
var sqlhost = viper.GetString("db.host")
func foo() {
log.Println(sqlhost)
}
I suspect that doing package variable initialization as you show will lead to the viper configuration not being complete before performing the GetString(), and therefore the zero (empty) string value is what is returned. Without seeing how you initialize your viper config, I'm guessing that it's not in an init() function, but is in a main() function that hasn't run yet when the package variable is assigned.
You should probably retrieve the viper.GetString("db.host") inside the highest level function that needs it rather than during package initialization.

Go compiler undefined method

I am getting a compiler error "w.Write undefined (type rest.ResponseWriter has no field or method Write)"
I created a bare bones test file and have the same problem:
package server
import (
"github.com/ant0ine/go-json-rest/rest"
)
func WriteTest(w rest.ResponseWriter) {
var bs []byte
w.Write(bs)
}
The method that the compiler says is not defined is definitely in the rest package.
The rest.ReponseWriter type has no Write, it has the following methods:
Header
WriteJson
EncodeJson
WriteHeader
However, it says in the comments that http.ResponseWriter methods are available by type assertion. So you should be able to write the following:
package server
import (
"github.com/ant0ine/go-json-rest/rest"
"net/http"
)
func WriteTest(w rest.ResponseWriter) {
var bs []byte
w.(http.ResponseWriter).Write(bs)
}
Write is defined on responseWriter. Note the lowercase r.

Go Global Variables and Scopes of slices

I am starting out with GO language, and getting an error I cannot figure out. How do I create a global slice that all functions within the module can use? Here is what I have:
package main
import (
"fmt"
)
type Req struct {
Req int
Name string
}
var Reqs []Req
func ReadReqs(fp string) {
var CReq Req;
CReq.Req = 1
CReq.Name = "first"
Reqs := append(Reqs, CReq)
}
func main() {
Reqs := make([]Req, 0)
if len(Reqs) > 0 {
fmt.Println(Reqs[0])
}
fmt.Println(Reqs)
}
This code will not compile because of the following error:
./question.go:18: Reqs declared and not used
I was thinking that declaring var Reqs []Req should declare the variable, but it does not seem to be aware of it inside the ReadReqs function. I do realize that globals are BAD but I would like to use global var for this simple program.
Okay first of all I'd recommend you to read Effective Go before continuing.
You are declaring your global variable using:
var Reqs []Req
Then re-declaring a variable with the same name using:
Reqs := ......
You are declaring two different variables.
var Name type also initializes the variable:
var s string
Is equivalent to:
s := ""
So this makes the following line useless:
Reqs = make([]Req, 0)
You can try your fixed code here (Golang Play).
With := you are declaring a new variable (not writing to the global) and that new variable at function scope is unused. (Has nothing to do with globals.)
You're re-declaring Reqs with the := operator. Drop the colon.
You should probably start with the basics first:
Tour of Go
How to Write Go Code
Effective Go

Resources