Importing external functions and logic from another go file inside same directory - go

I am new to golang and have been loving it so far. So far I've been writing all my applications logic inside the main.go and it is starting to get quite cumbersome with so much text on the screen. I cannot for the life of me figure out how to import external functions that are located in another .go file. Here is a basic example of what I'm trying to accomplish
main.go
package main
func main() {
SayHello() //THIS IS THE FUNCTION IMPORTED FROM hello.go
{
hello.go
package hello
import "fmt"
func SayHello() {
fmt.Println("Hello!")
{
project structure
/
-main.go
-hello.go
I know this is a fairly simple question but everything I try will result in an error in my console. All I want in this example is to export the SayHello function from the hello.go file into the main.go file, and as far as I understand anything exported must start with a capital letter. The whole go.mod file and package declaration at the top if each file confuses me and I have not been able to figure this out for hours.

You can only have a single package per directory. If you want the code in hello.go to live in a separate package, you need to move it into a subdirectory.
First, this assumes that you've initialized your project using go mod init <something>. For the purposes of this example, we'll start with:
go mod init example
This creates our go.mod file. Next, we set up the correct directory structure:
.
├── go.mod
├── hello
│   └── hello.go
└── main.go
hello.go is correct as written (well, once you fix the syntax errors in your posted code). We'll need to add an import to main.go:
package main
import "example/hello"
func main() {
hello.SayHello() //THIS IS THE FUNCTION IMPORTED FROM hello.go
}
This will build an executable that produces the expected output:
$ go build
$ ./example
Hello!

Related

Golang - package name as double underscore

In my protobuf generated go code, the package is:
package __
What does the double underscore mean, does it means the same as folder name ?
Is there a document for this, I searched but didn't found any. And the code can compile without error.
Yes it means the same directory. Let's look at the following code.
Directory Structure
.
├── go.mod
├── greet
│ └── greet.go
└── main.go
Content in greet.go
package __
import "fmt"
func Hello(name string) {
fmt.Printf("Hello %s\n", name)
}
Content in main.go
package main
import greet "playground/greet"
func main() {
greet.Hello("Eric")
}
Current Directory
$ pwd
/Users/thedatageek/Codes/go-playground
Unfortunately I also couldn't find any docs for go.
But it seems that its kinda good thing. You really don't need to name the package. You just name the directory and the package name would be automatically the same.
Note: This is definitely not the grpc or protobuf thing. It is however a customary that if you have generated proto stub from a proto file and if you add some additional utility file you may put those into a dir and then import it directly via directory name. For example the following github repos
https://github.com/Ash110/gRPC-Logger
https://github.com/dist1ll/cache-prototype
https://github.com/kamensotirov99/int-gateway
https://github.com/rachaelyychen/go-gee
https://github.com/suvvm/ToadOCREngine
https://github.com/denyami/drawing-api

Call function in another files

I don't know how I can use function in another file.
my project architecture:
.
├── main.go
└── src
└── function.go
1 directory, 2 files
main.go
package main
import "src/funcrion"
func main() {
funcrion.Display();
}
function.go
package src
import "fmt";
func Display() {
fmt.Println("Hello World");
}
For start my project I use:
go run main.go
error:
main.go:3:8: cannot find package "src/funcrion" in any of:
/usr/local/opt/go/libexec/src/src/funcrion (from $GOROOT)
/Users/clementbolin/go/src/src/funcrion (from $GOPATH)
In first, I want to resolve this problem. In second time I want to know what is the best option for compile a real project with more 10 files for example, do I need to use Makefile? Or like in Rust go has package manager?
When you do import "src/funcrion" the go compiler will try to search for this in GOPATH and GOROOT, as you see in your error message. It does not try to search in the current folder. Since it doesn't find a package with that name in either GOPATH or GOROOT, it gives you that error.
A good way to reference "the current folder" would be using go modules. On the root of your project do $ go mod init myproject. (replace myproject for a more appropriate name for your project)
After you do that, you can use "myproject" to reference the project folder in package names, like:
package main
import "myprject/src"
func main() {
src.Display();
}
Also note that the import goes only up to the package name and not the file name. So, in your case, you shouldn't do import myproject/src/function just because you have a function.go file inside a src package.
And since your Display function is inside the src package, you refer to it simply with src.Display() after importing the package. No need to specify the name of the file anywhere.
You can read more about go modules here: https://blog.golang.org/using-go-modules
Another tip is to not use src as a package name. In Go, it's common to not have a "src" folder, and as a package name is also not very good. For instance, see the line that reads src.Display(). Instinctively, i would read this as something like "the Display of the source", which has no meaning. But if instead of src you name your package text, that same line would read text.Display() which would read as "display some text", which is more accurate and meaningful to what the function is doing.
I believe the package name is src but I see you are trying to import src\funcrion There is no such package called funcrion.
I think you should just do something like this main.go
package main
import "src"
func main() {
src.Display();
}
or if you would like to call your src package as funcrion, then just import it like below,
import funcrion "src"
And make sure your file structure is as below and inside $GOPATH
Users
└── clementbolin
└── go
└── src
├── main.go
└── src
└── function.go

How can I resolve dependencies in nested application binary in Go project?

This sounds stupid, but I am trying for build my new golang project for a while now and I am stuck with following error
can't load package: package github.com/kuskmen/yamq/cmd/yamq-client: found packages main (main.go) and yamqclient (yamq-client.go) in C:\projects\yamq\cmd\yamq-client
I know this should be straightforward to fix, but I come from .NET and I am still not experienced in Go projects and its dependency resolution model hence the struggle.
My project structure looks like so
/yamq
/cmd
/yamq-client // yamq client application binary
main.go // package main
yamq-client.go // package yamqclient
/yamq-server // yamq server application binary
main.go // package main
yamq-server.go // package yamqserver
go.mod // contains only "module github.com/kuskmen/yamq" for now
... // some library files that will probably be moved to /shared folder
so far so good, when I do go build in outermost directory ( /yamq ) it is building successfully (or at least it is not showing any errors), but when I try to build either yamq-client or yamq-server binaries I get the aforementioned error and every time I try to google it or find something useful I got some old article or answer that dates back 2013-2016 that suggests something about $GOPATH and etc which shouldn't be the case here since I am trying to use go modules.
Help a fellow .NET developer join Go community by explaining him how exactly modules work cause I found this and this useless or at least I am missing the point, thanks in advance!
To follow up from my comment above:
From https://golang.org/doc/code.html:
Go programmers typically keep all their Go code in a single workspace.
A workspace contains many version control repositories (managed by Git, for example).
Each repository contains one or more packages.
Each package consists of one or more Go source files in a single directory.
The path to a package's directory determines its import path.
For your project, I'd do something like this:
$ tree
.
├── clientlib
│   └── lib.go
├── cmd
│   ├── client
│   │   └── main.go
│   └── server
│   └── main.go
├── go.mod
└── serverlib
└── lib.go
5 directories, 5 files
$ cat go.mod
module myproject.com
The module name is arbitrary (could be github.com/yourname/yourproject).
For the server side:
$ cat serverlib/lib.go
package serverlib
import "fmt"
func Hello() {
fmt.Println("Hello from serverlib.Hello")
}
$ cat cmd/server/main.go
package main
import (
"fmt"
"myproject.com/serverlib"
)
func main() {
fmt.Println("Running server")
serverlib.Hello()
}
And now we can build and run it:
$ go build -o server cmd/server/main.go
$ ./server
Running server
Hello from serverlib.Hello
The client side looks symmetrical.
Variations: you could name the .go files in cmd/... by their actual binary names - like server.go and client.go. The package in each is still main, but then go build creates an executable with the file's name (sans the .go) without needing to -o explicitly.

Relative imports in Go

I have a go Project with the following directory structure
utils(pkg)
| auth.go (has a function names test1)
controllers(pkg)
| login.go (has a function names test2)
I am trying to access function test1 from login.go. Here is what I have done
import "../utils"
func test2(c *gin.Context) bool{
utils.test1()
}
But I always get Unresolved reference test1. I am new to go . Can anyone help why I am getting this error?
No there is no relative import in Go.
you should use the absolute path considering GOPATH:
The GOPATH environment variable specifies the location of your workspace. It is likely the only environment variable you'll need to set when developing Go code. To get started, create a workspace directory and set GOPATH accordingly. see: https://golang.org/doc/code.html#GOPATH
Import paths
An import path is a string that uniquely identifies a package. A package's import path corresponds to its location inside a workspace
or in a remote repository (explained below).
The packages from the standard library are given short import paths
such as "fmt" and "net/http". For your own packages, you must choose a
base path that is unlikely to collide with future additions to the
standard library or other external libraries.
If you keep your code in a source repository somewhere, then you should use the root of that source repository as your base path. For
instance, if you have a GitHub account at github.com/user, that should
be your base path.
Note that you don't need to publish your code to a remote repository
before you can build it. It's just a good habit to organize your code
as if you will publish it someday. In practice you can choose any
arbitrary path name, as long as it is unique to the standard library
and greater Go ecosystem.
Example:
This example assumes you have set GOPATH=/goworkdir in your OS environment.
File: goworkdir/src/project1/utils/auth.go
package utils
func Test1() string {
return "Test1"
}
File: goworkdir/src/project1/controllers/login.go
package controllers
import "project1/utils"
func Test2() string {
return utils.Test1()
}
File: goworkdir/src/project1/main.go
package main
import (
"fmt"
"project1/controllers"
)
func main() {
fmt.Println(controllers.Test2())
}
Now if you go run main.go you should see output:
Test1
This is now different since the introduction of go modules, from go 1.11.
Thus, if you switch to go modules, and if your module is called "m", then the idiomatic way to do relative imports in your project tree would be to use: import "m/utils" and import "m/controllers" in places where you need to import those packages in your project.
For details, see:
https://github.com/golang/go/wiki/Modules#do-modules-work-with-relative-imports-like-import-subdir
GoLand users - by default these forms of imports appear as errors in the IDE. You need to enable Go Modules integration in settings
Here is another example project structure with file contents required to import correctly:
test1/
utils/
texts.go
main.go
go.mod
with following contents:
go.mod:
module mycompany.com/mytest
go 1.15
utils/texts.go (to make a function visible from a different package, it needs to start with an uppercase letter):
package utils
func GetText() string {
return "hello world"
}
main.go (only the full import name is supported, there is no shortcut to import from the same module easier):
package main
import (
"fmt"
"mycompany.com/mytest/test1/utils"
)
func main() {
fmt.Println(utils.GetText())
}
Given this directory configuration:
.
├── controllers
│   └── login.go
├── main.go
└── utils
└── auth.go
File main.go:
package main
import "./controllers"
func main() {
controllers.Test2("Hello")
}
File controllers/login.go:
package controllers
import "../utils"
func Test2(msg string) {
utils.Test1(msg)
}
File utils/auth.go:
package utils
import . "fmt"
func Test1(msg string) {
Println(msg)
}
Result works:
$ GO111MODULE=auto go build -o program main.go
$ ./program
Hello
So what you wanted to do works. The only difference is that I've used upper case function names, because it's required to export symbols.
I think you can just crate a vendor directory next to your source file, which acts like a relative GOPATH, and then create a relative symlink, which links to the package you want to import inside the vendor directory, and then import the package as if the vendor directory is your $GOPATH/src/.
It's possible as of Go 1.16, although still not as straightforward as it could be, by editing the go.mod file to resolve the package name to a relative path:
if you have a hello and a greeting packages side by side (hello contains main.go):
<home>/
|-- greetings/
|--go.mod <- init this as infra/greetings
|--greetings.go <- let's say that this package is called greetings
|-- hello/
|--go.mod <- init this as whatever/hello
|--main.go <- import infra/greetings
then edit hello's go.mod file and get the package:
go mod edit -replace infra/greetings=../greetings
go get infra/greetings
go mod tidy
There's a full example in the official documentation but hey, this might change again in the next version of Go.

Does it make sense to have two packages in the same directory?

I have a project that provides a library (exports some funcs) and also must provide a command-line interface (there must be an executable file).
Example of directory structure:
whatever.io/
myproject/
main.go
myproject.go
The go compiler needs the package main and func main to start execution. My library needs the package myproject where I put stuff on it. This is what the go tool says when I am building another project that tries to import myproject:
main.go:5:2: found packages myproject (myproject.go) and main (main.go) in $GOPATH/src/whatever.io/myproject
So I believe there is no way to do it.
Should I move the library or the CLI to another package?
Just move your packages inside a new folder within the same directory of main.go.
Remember to import the new package from the reference of the $GOPATH.
Example:
user#user:~/p/go/test/so-multipack$ ls -R
.:
a main.go
./a:
a.go
user#user:~/p/go/test/so-multipack$ cat main.go
package main
import (
"../so-multipack/a"
)
func main(){
a.Hello()
}
user#user:~/p/go/test/so-multipack$ cat a/a.go
package a
import (
"fmt"
)
func Hello(){
fmt.Println("hello from a")
}
user#user:~/p/go/test/so-multipack$ go run main.go
hello from a
user#user:~/p/go/test/so-multipack$ go build
user#user:~/p/go/test/so-multipack$ ls
a main.go so-multipack
user#user:~/p/go/test/so-multipack$
Useful link:
go build vs go build file.go
You cannot have two packages per directory, hence the error. So the solution as #Larry Battle said to move your myproject.go to a new directory.
From How to write go code
Go code must be kept inside a workspace. A workspace is a directory
hierarchy with three directories at its root:
src contains Go source files organized into packages (one package per directory),
pkg contains package objects, and
bin contains executable commands.
In most cases, no. However, there is an exception for unit tests.
Working Example:
Here are 2 different packages (mypackage and mypackage_test) in 1 directory (mypackage). The compiler will not complain about this.
mypackage folder:
mypackage/
foo.go
foo_test.go
mypackage/foo.go:
package mypackage
func Add(a int, b int) int {
return a + b
}
mypackage/foo_test.go:
package mypackage_test
// Unit tests...
Rules:
The 2 packages must have the following names:
NameOfDirectory.
NameOfDirectory + _test.
The names of the files in the _test package must end with _test.go
If you're receiving a confusing compiler error along the lines of found packages "foo" and "bar", you've probably broken one or more of these rules.
You can't have two golang files in one directory with two packages. So you need to move main.go out of myproject.
the directory structure before move
whatever.io/
go.mod
myproject/
main.go
myproject.go
After move
whatever.io/
go.mod
main.go
myproject/
myproject.go
And you need to change your main.go's import path. If the module name is aaa
Before
import "aaa"
Need change to this
import "aaa/myproject"

Resources