I'm trying to create a module that contains multiple packages but I don't understand why I'm getting errors.
Layout:
λ ~/code/go-test/src/mod-test/ » tree
.
├── cmd
│ └── a.go
├── go.mod
├── main.go
└── pkg
└── foo
└── b.go
3 directories, 4 files
main.go:
package main
import (
"fmt"
"github.com/go-test/mod-test/cmd"
)
func main() {
fmt.Println("main")
A()
}
cmd/a.go:
package cmd
import (
"fmt"
"github.com/go-test/mod-test/pkg/foo"
)
func A() {
fmt.Println("a")
B()
}
pkg/foo/b.go:
package foo
import "fmt"
func B() {
fmt.Println("B")
}
go.mod:
module github.com/go-test/mod-test
go 1.12
I get the following error:
λ ~/code/go-test/src/mod-test/ » go build
# github.com/go-test/mod-test/cmd
cmd/a.go:5:2: imported and not used: "github.com/go-test/mod-test/pkg/foo"
cmd/a.go:10:2: undefined: B
Can anyone help explain what I've done wrong and why I get the error?
Thanks,
There is bug in the cmd/a.go. You did not use "github.com/go-test/mod-test/pkg/foo". Also B() is under github.com/go-test/mod-test/pkg/foo package, so you have to specify it. See below:
package cmd
import (
"fmt"
"github.com/go-test/mod-test/pkg/foo"
)
func A() {
fmt.Println("a")
// B()
foo.B()
}
There is another way to avoid this. If you don't want to use the package name, simply just put a . before importing a package. By doing that you can call a public fn or use a public var of that package. After doing that your main.go and cmd/a.go files look like below:
main.go:
package main
import (
"fmt"
. "github.com/go-test/mod-test/cmd"
)
func main() {
fmt.Println("main")
A()
}
cmd/a.go:
package cmd
import (
"fmt"
. "github.com/go-test/mod-test/pkg/foo"
)
func A() {
fmt.Println("a")
B()
}
Related
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"
}
I'm writing my first go code and I'm trying to convince myself what I'm doing is not wrong.
anyway, here the project the tree structure.
.
├── helpers
│ └── common.go
├── logger
│ └── util.go
├── logger_example
└── runner.go
The main file to look over here is logger/util.go which look like this.
package logger
import (
"log"
"os"
)
type Logger struct {
*log.Logger
}
func (l *Logger) Info(v ...interface{}) {
l.SetPrefix("Info: ")
l.Println(v...)
}
func (l *Logger) Error(v ...interface{}) {
l.SetPrefix("Error: ")
l.Println(v...)
}
func (l *Logger) Warn(v ...interface{}) {
l.SetPrefix("Warn: ")
l.Println(v...)
}
func (l *Logger) Debug(v ...interface{}) {
l.SetPrefix("Debug: ")
l.Println(v...)
}
func NewLogger() *Logger {
logger := log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile)
return &Logger{logger}
}
As you all can see, I'm just setting the prefix to "INFO | WARN | ERROR | DEBUG"
On the main package I have safely created a Logger instance and VOILA it worked.
Only until I decided to add a helpers package and now things do not look the way I wanted.
since the logger.Logger instance created inside main package, I have to pass it reference to every since package function where I want to invoke the logger statement. (see the below example ..)
// dodly_logger/logger/common.go
package helpers
import "dodly_logger/logger"
func Display(dodlyLogger *logger.Logger) {
dodlyLogger.Info("Inside a helper package")
}
The Main package..
package main
import (
logger "dodly_logger/logger"
helpers "dodly_logger/helpers"
)
func main() {
dodlyLogger := logger.NewLogger()
dodlyLogger.Info("INFO MESSAGE")
dodlyLogger.Error("ERROR MESSAGE")
// Ehh, I have to pass the dodlyLogger ..
helpers.Display(dodlyLogger)
}
Ok, now I know my GOLang knowledge is not complete hence I'm hoping people over here can point me how can I write this more clinically wherein I do not have to pass the reference of the logger.Logger to every function for which I need to log.
Create a package level variable with var.
package main
import (
logger "dodly_logger/logger"
helpers "dodly_logger/helpers"
)
var dlogger logger.Logger
func init() {
dlogger = logger.NewLogger()
}
func main() {
dlogger.Info("Starting Main")
a()
}
func a() {
dlogger.Info("in a")
}
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)
}
I've got 2 sibling files: main and test_two. In each is the file main.go and test_two.go respectively. In one I've got a custom struct and in the other I want to run a function with that struct as a param. I'm getting the error "undefined: Struct".
package main
import "github.com/user/test_two"
type Struct struct {
Fn string
Ln string
Email string
}
func main() {
foo := new(Struct)
foo.Fn = "foo"
foo.Ln = "bar"
foo.Email = "foo#bar.com"
test_two.Fn(foo)
test_two.go:
package test_two
import (
"fmt"
)
func Fn(arg *Struct) {
fmt.Println(arg.Fn)
}
Some rules to live by:
Don't define types in main (usually)
Don't try to import main in other packages
Don't try to import both ways (import cycle)
Always import from a lower level into a higher one (so mypkg into main)
All folders are packages, put related data/functions in them and name them well
You probably want something like this:
app/main.go
app/mypkg/mypkg.go
with contents for main.go:
// Package main is your app entry point in main.go
package main
import (
"stackoverflow/packages/mypkg"
)
func main() {
foo := mypkg.Struct{
Fn: "foo",
Ln: "foo",
Email: "foo#bar.com",
}
mypkg.Fn(foo)
}
Contents for mypkg.go:
package mypkg
import (
"fmt"
)
type Struct struct {
Fn string
Ln string
Email string
}
func Fn(s Struct) {
fmt.Printf("func called with %v\n", s)
}
Go structure:
|--main.go
|
|--users
|
|---users.go
The two files are very simple:
main.go:
package main
import "./users"
func main() {
resp := users.GetUser("abcde")
fmt.Println(resp)
}
users.go:
package users
import "fmt"
func GetUser(userTok string) string {
fmt.Sprint("sf")
return "abcde"
}
But it seems fmt is not accessible in main.go. When I try to run the program, it gives
undefined: fmt in fmt.Println
Anybody knows how to make fmt accessible in main.go?
You need to import fmt in main as well.
Simply write "fmt" in import() in main.go and it should run.
import(
"fmt"
"./users"
)