exported methods not available in same package - go

I have a small go lang project which in the main.go file has a few handlers that refer to session related methods in a session.go file. Both have package main at the top of the file. The functions in the session.go file all begin with an uppercase letter (i.e. they are public/exported methods). Yet when I run the main.go file, it says the methods located in session.go and called from main.go are undefined. Why is that, how to fix it.
I am running the project like go run main.go
main.go
func logout(w http.ResponseWriter, r *http.Request) {
ClearSession(w, r)
....
}
session.go
func ClearSession(w http.ResponseWriter, r *http.Request) {
}

As #ptd said, the command needs all the files named.
I prefer use another package:
/ main.go
|_session/
|_session.go
|_validations.go
|_errors.go
So, you can organize your code and simplify your named files.
e.g.:
file: main.go
package main
import "session"
func main() {
var validator session.Validator
var session session.Session
...
if session.IsValid() == false {
// return session.InvalidSession
fmt.Printf("ERROR: %v", session.InvalidSession)
}
}
file: errors.go
import "errors"
var (
InvalidSession = errors.New("[Your error message]"
)
Then you can use:
go run main.go

Related

passing map between packages in golang

In golang, I know that map is passed between functions in the form of reference, but I encountered a strange situation today. The running result of the code is not what I imagined. I simplified it into the following lines of code.
.
├── go.mod
├── main.go
├── packageA
│   └── a.go
└── packageB
└── b.go
main.go file
package main
import (
"gostudy/packageA"
"gostudy/packageB"
)
func main() {
packageB.UseMap(packageA.M, packageA.InitMap)
}
a.go
package packageA
var M map[string]string
func InitMap() {
M = make(map[string]string)
M["hello"] = "go"
}
b.go
package packageB
import "fmt"
func UseMap(m map[string]string, callback func()) {
callback()
fmt.Println(m)
}
As you can see, there is only one variable globally declared in the a.go file. I thought the above program should output map[hello:go], but it actually outputs an empty map[]. I'm very confused about this and hope to get an answer.
You're passing the old value of the map as a parameter, before you invoke the function to replace it with a new version of the map.
Let's say packageA.M contains the value map[string]string{"foo": "bar"}. The main() function reads the variable and gets a reference to this map, and passes it and the function to packageB.UseMap().
Inside packageB.UseMap(), your code calls packageA.InitMap() via the callback. This does not modify the existing map; instead, it creates a new map, assigns it to the global variable, and populates it. Anything that had a copy of the old map is unaffected, and the code you show doesn't re-read the value of packageA.M.
I'd recommend dispensing with the global variable entirely: it can make the code hard to test and there are potential problems once you start using goroutines. Just have your setup function return the new map.
package packageA
func InitMap() map[string]string {
return map[string]string{"hello": "go"}
}
package packageB
func UseMap(callback func() map[string]string) {
m := callback()
fmt.Println(m)
}
package main
import "packageA"
import "packageB"
func main() {
packageB.UseMap(packageA.InitMap)
}
Just as a side note to the accepted anwer, if you take a look at this:
// ...
import (
"reflect"
"fmt"
)
// ... other functions
// I defined all of the functions in a single paackage, so I can access them both here
func UseMap(m map[string]string, callback func()) {
fmt.Println(reflect.ValueOf(m).Pointer() == reflect.ValueOf(M).Pointer()) // prints true, they have the same reference
callback()
// inside callback, M global variable takes a whole new reference
// when "M = make(...)"
// and then =>
fmt.Println(reflect.ValueOf(m).Pointer() == reflect.ValueOf(M).Pointer()) // prints false
}
If you want to avoid this without changing your apis, you can do this in your package A:
package packageA
var M map[string]string = make(map[string]string)
func InitMap() {
M["hello"] = "go"
}

plugin and package scoped global variables

I have a Go package to manage configuration. The package has a non-exported variable initialized in an init function that holds the configuration data. The user interacts with the configuration through exported functions that internally access the global variable. Something like this
pakage config
var gConfig ...
func init() {
gConfig = ...
}
func Value(name string) (string, error) {
return gConfig.value(name)
}
I’m considering the use of plugins and explore the impact on my config package.
If the plugin imports the config package and calls some of its exported functions, what gConfig variable will be used? Will the plugin have its own internal instance of config with its own gConfig variable initialized when the plugin is loaded, or will the plugin be linked dynamically at load time to use the main program gConfig variable initialized at program startup?
as per documentation
Package plugin implements loading and symbol resolution of Go plugins.
When a plugin is first opened, the init functions of all packages not
already part of the program are called. The main function is not run.
A plugin is only initialized once, and cannot be closed.
Also, you cannot import the same plugin twice.
Will the plugin have its own internal instance of config with its own gConfig variable initialized when the plugin is loaded
the plugin will have its own variable within its scope.
If the plugin imports the config package and calls some of its exported functions, what gConfig variable will be used ?
the variable defined within the package, as you demonstrated.
To check that out, write a small demonstration. Go is very straightforward and efficient, doing it takes very little time, see.
$ tree .
.
├── main.go
├── plug
│   └── plugin.go
└── plugin.so
1 directory, 3 files
// $ cat plug/plugin.go
package main
var pkgGlobal = map[string]string{}
func Set(k, v string) {
pkgGlobal[k] = v
}
func Get(k string) string {
return pkgGlobal[k]
}
// $ cat main.go
package main
import (
"fmt"
"plugin"
)
func main() {
p, err := plugin.Open("plugin.so")
if err != nil {
panic(err)
}
var get func(string) string
{
x, err := p.Lookup("Get")
if err != nil {
panic(err)
}
get = x.(func(string) string)
}
var set func(string, string)
{
x, err := p.Lookup("Set")
if err != nil {
panic(err)
}
set = x.(func(string, string))
}
set("tomate", "rouge")
fmt.Println(get("tomate"))
fmt.Println(get("notomate"))
}
build and run
$ go build -buildmode=plugin -o plugin.so plug/plugin.go
$ go run main.go
rouge

Go build project with cmd and pkg layout - build error

I'm trying to build a Go project using the layout as described in Go Project Layout
I'm using go 1.9.2 on Ubuntu. My project layout is as follows
$GOPATH/src/github.com/ayubmalik/cleanprops
/cmd
/cleanprops
/main.go
/internal
/pkg
/readprops.go
The file cmd/cleanprops/main.go is referring to the cleanprops package i.e.
package main
import (
"fmt"
"github.com/ayubmalik/cleanprops"
)
func main() {
body := cleanprops.ReadProps("/tmp/hello.props")
fmt.Println("%s", body)
}
The contents of internal/pkg/readprops.go are:
package cleanprops
import (
"fmt"
"io/ioutil"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func ReadProps(file string) string {
body, err := ioutil.ReadFile(file)
check(err)
fmt.Println(string(body))
return body
}
However when I build cmd/cleanprops/main.go, from inside directory $GOPATH/src/github.com/ayubmalik/cleanprops, using command:
go build cmd/cleanprops/main.go
I get the following error:
cmd/cleanprops/main.go:5:2: no Go files in /home/xyz/go/src/github.com/ayubmalik/cleanprops
What am I missing?
The document suggests this structure:
$GOPATH/src/github.com/ayubmalik/cleanprops
/cmd
/cleanprops
/main.go
/internal
/pkg
/cleanprops
/readprops.go
Import the package like this. The import path matches the directory structure below $GOPATH/src.
package main
import (
"fmt"
"github.com/ayubmalik/cleanprops/internal/pkg/cleanprops"
)
func main() {
body := cleanprops.ReadProps("/tmp/hello.props")
fmt.Println("%s", body)
}

Go cannot call NewRouter() function [duplicate]

This question already has answers here:
go build works fine but go run fails
(3 answers)
Closed 7 years ago.
I'm new to Go, but I'm trying to create a RESTful API using Gorilla Mux to create my router based on this article http://thenewstack.io/make-a-restful-json-api-go/
I have a Router file with the below code in it.
package main
import (
"net/http"
"github.com/gorilla/mux"
)
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
type Routes []Route
func NewRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(route.HandlerFunc)
}
return router
}
var routes = Routes{
Route{
"Index",
"GET",
"/",
Index,
},
}
And in my Main.go I have this:
package main
import (
"log"
"net/http"
)
func main() {
router := NewRouter()
log.Fatal(http.ListenAndServe(":8080", router))
}
From what I know about Go and how to call a method in one file from another this should work. But when I run: go build Main.go I get this error in my console:
go run Main.go
# command-line-arguments
./Main.go:10: undefined: NewRouter
I've run go get in my src folder which has all my files in it to get gorilla, but that didn't fix it. What am I doing wrong here?
If your main package consists of multiple .go files, you have to pass all to go run, e.g.:
go run Main.go Router.go

Running multi-file go program

So I'm pretty new to go and I'm trying to follow this tutorial -
http://thenewstack.io/make-a-restful-json-api-go/
Right now, this is my file structure -
EdData/
dataEntry/
populateDb.go
main.go
handlers.go
routes.go
When I run go run main.go, I get this error ./main.go:11: undefined: NewRouter
This is what my main.go looks like -
package main
import (
"net/http"
"log"
)
func main() {
router := NewRouter()
log.Fatal(http.ListenAndServe(":8080", router))
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
This is what my routes.go looks like
package main
import (
"net/http"
"github.com/gorilla/mux"
)
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
type Routes[]Route
func NewRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(route.HandlerFunc)
}
return router
}
var routes = Routes{
Route {
"Index",
"GET",
"/",
Index,
},
}
and this is what my handlers.go looks like
package main
import (
"fmt"
"net/http"
)
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "WELCOME!")
}
When I try and build routes.go, I get that Index is undefined, and when I try and build handlers.go, I get
# command-line-arguments
runtime.main: undefined: main.main
How do I get this to run? Also, where do I execute the go run command? Do I need to manually build all the dependent files?
From the go run help:
usage: run [build flags] [-exec xprog] gofiles... [arguments...]
Run compiles and runs the main package comprising the named Go source files.
A Go source file is defined to be a file ending in a literal ".go" suffix.
Only the files passed to go run will be included in the compilation (excluding imported packages). Therefore, you should specify all of your Go source files when using go run:
go run *.go
# or
go run main.go handlers.go routes.go

Resources