I'm following the official Go tutorial: https://golang.org/doc/code.html
But instead of doing things via the command line I'm using GoLand. I'm able to run the program and see "Hello World" printed when everything is contained inside the HelloWorld.go package, but when I add the morestrings package and try to import it in HelloWorld.go I get an import error (Cannot resolve file 'morestrings'):
package main
import (
"morestrings"
"fmt"
)
func main() {
fmt.Println(morestrings.ReverseRunes("!oG ,olleH"))
}
Here's what I've defined the morestrings package to be:
package morestrings
// ReverseRunes returns its argument string reversed rune-wise left to right.
func ReverseRunes(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
I've set the GOPATH in project settings to the root directory of my project (GoGoHelloWorld). My understanding is that Go will look for imports starting at GOPATH, so I would expect it to find the morestrings package. Here's the file structure:
First, I think you can take a look at this go project layout which may diffs with other language like C++ or Java.
Second, I would like using go module.
If your go path is GOPATH=/Users/.../IdeaProjects/FinalGoHelloWorld.
I am assuming you have created a project "GoGoHelloWorld" inside "FinalGoHelloWorld".
Your import statement is wrong, you should use "GoGoHelloWorld/src/morestrings"
When you try to import a package in GO, it doesn't look for that package everywhere in the whole file system, it looks for that package in specific folders.
These folders are the src folder inside your GOROOT and GOPATH directory.
All your code should be place inside this GOPATH's src folder.
You mentioned in the comments section GOPATH=/Users/.../IdeaProjects/FinalGoHelloWorld. So you must create a src folder inside this directory and all the code goes inside src.
So your GoGoHelloWorld folder's full path must be /Users/.../IdeaProject/FinalGoHelloWorld/src/GoGoHelloWorld, so now your import should look more like
import (
"GoGoHelloWorld/src/morestrings"
"fmt"
)
For reference, since your GOROOT is GOROOT=/usr/local/go your fmt package(folder) will be loacted at /usr/local/go/src/fmt
I would also recommend changing the GOPATH folder name from FinalGoHelloWorld to something more generic like GoWorkspace. So inside GoWorkspace/src you could create multiple projects folders with specific name.
One last thing, create two more folders, bin and pkg, along with srcinside GOPATH
Related
This is my code structure:
addition
|_ summing
|_ sum_prg.go
|_ addition.go
|_ go.mod
Contents of go.mod
module addition
go 1.14
Contents of sum_prg.go
package summing
func sumIt(ii int) int {
return ii + 10
}
Contents of addition.go
package main
import (
"fmt"
"summing"
)
func main() {
fmt.Println("hi")
fmt.Println(summing.sumIt(1))
}
Here's the steps I've run:
Inside addition folder, go mod init addition
Inside summing folder, go build
Back in addition, go install addition
In step 3 I get an error "addition.go:5:2: package summing is not in GOROOT (c:\go\src\summing)"
This is my first go programming attempt.
I can successfully follow the steps listed here, but when I try to follow the same steps, I see the error mentioned above.
Do I always need to have module names of the form somethng.com/else?
You can see from the module FAQ
Do modules work with relative imports like import "./subdir"?
No. See #26645, which includes:
In modules, there finally is a name for the subdirectory.
If the parent directory says "module m" then the subdirectory is imported as "m/subdir", no longer "./subdir".
So, as commented, use "addition/summing" (with exported method name) for your import from main.
I'm just starting to learn Go and I'm wondering how to best organize my project and import packages. I created a project at $GOPATH/src/my_project. It contains the file main.go and the folder foo containing the file bar.go.
$GOPATH/src/my_project
main.go
foo/
bar.go
My main.go looks as follows
package main
import (
"./foo"
"fmt"
)
func main() {
fmt.Println("Main")
foo.Baz()
}
Here is the foo.go
package foo
import "fmt"
func Baz() {
fmt.Println("Baz")
}
It works the way I expect it to, but I wonder if this is really the right way to structure a project and import packages, because most tutorials only import packages from github and never from local.
Thanks for your answers..
Relative imports are possible in Go but they are not encouraged to be used.
Instead you always use the full path of the package. In your case that would be my_project/foo. This is is relative to the GOPATH/src folder.
However, since we have Go modules now which make things a tiny bit more complicated to start with but have a lot of advantages in the long run.
Just earlier today I gave a step by step guide on how to set up a new project with Go modules: After go install the import doesn't recognize the package
The module name in this guide is the basis for your project then and all paths in the module build on that path. Let me give an example:
Let's say you name your module github.com/yourName/myProject. Then you can import the subpackage foo with github.com/yourName/myProject/foo.
Note: The module path should be the same as the git URL, that way you can just get the module with go get. If you don't plan on ever uploading the project to github or another git URL, you should still choose a unique name. Starting with a domain you own is a good idea -- for uniqueness.
This is my code structure:
addition
|_ summing
|_ sum_prg.go
|_ addition.go
|_ go.mod
Contents of go.mod
module addition
go 1.14
Contents of sum_prg.go
package summing
func sumIt(ii int) int {
return ii + 10
}
Contents of addition.go
package main
import (
"fmt"
"summing"
)
func main() {
fmt.Println("hi")
fmt.Println(summing.sumIt(1))
}
Here's the steps I've run:
Inside addition folder, go mod init addition
Inside summing folder, go build
Back in addition, go install addition
In step 3 I get an error "addition.go:5:2: package summing is not in GOROOT (c:\go\src\summing)"
This is my first go programming attempt.
I can successfully follow the steps listed here, but when I try to follow the same steps, I see the error mentioned above.
Do I always need to have module names of the form somethng.com/else?
You can see from the module FAQ
Do modules work with relative imports like import "./subdir"?
No. See #26645, which includes:
In modules, there finally is a name for the subdirectory.
If the parent directory says "module m" then the subdirectory is imported as "m/subdir", no longer "./subdir".
So, as commented, use "addition/summing" (with exported method name) for your import from main.
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.
In the process of learning go I was playing around with making my own libraries. Here is what I did: in my $GOPATH/src I have two folders: mylibs and test. The test folder has a file called test.go which contains
package test
import "mylibs/hi/saysHi"
func main() {
saysHi.SayHi()
}
The mylibs folder contains another folder called hi, which has a file called saysHi.go containing:
package saysHi
import "fmt"
func SayHi() {
fmt.Printf("Hi\n")
}
So the directory structure looks like this:
GOPATH/src
test
test.go
mylibs
hi
saysHi.go
The problem is that when I try to compile test it complains saying
cannot find package "mylibs/hi/saysHi" in any of:
[...]
$GOPATH/src/mylibs/hi/saysHi (from $GOPATH)
I have deliberately made the directory structure deeper than necessary. If I make a simpler directory structure where I place saysHi.go in $GOPATH/saysHi/saysHi.go then it works.
But I don't see a reason for why this wouldn't work. Any ideas?
Generally speaking, your directory name should match the package name. So if you define
package saysHi
and want to import it with
import "mylibs/hi/saysHi"
you should place it in a structure like this:
mylibs
hi
saysHi
saysHi.go
The name of the .go file(s) inside the package makes no difference to the import path, so you could call the .go file anything you like.
To explain it a bit further, the import path you use should be the name of the directory containing the package. But, if you define a different package name inside that directory, you should use that name to access the package inside the code. This can be confusing, so it's best to avoid it until you understand where it's best used (hint: package versioning).
It gets confusing, so for example, if you had your package in the path
mylibs
hi
saysHi.go
And inside saysHi.go defined,
package saysHi
Then in test.go you will import it with
import "mylibs/hi"
And use it with
saysHi.SayHi()
Notice how you import it with the final directory being hi, but use it with the name saysHi.
Final note
Just in case you didn't know the following: your test file is called test.go, and that's fine, if it's just as an example, and not an actual test file for saysHi.go. But if it is/were a file containing tests for saysHi.go, then the accepted Go standard is to name the file saysHi_test.go and place it inside the same package alongside saysHi.go.
One more final note
I mentioned how you are allowed to choose a different package name from the directory name. But there is actually a way to write the code so that it's less confusing:
import (
saysHi "mylibs/hi"
)
Would import it from the mylibs/hi directory, and make a note of the fact that it should be used with saysHi, so readers of your code understand that without having to go look at the mylibs/hi code.