70

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?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
codec
  • 7,978
  • 26
  • 71
  • 127

7 Answers7

67

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
Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
  • 33
    So you mean that if I change the repository where I am keeping my code then I need to modify all import statements in my code? This doesn't seems right. – Hafiz Oct 16 '18 at 11:13
  • 1
    This answer is only partially correct. If you use GOPATH, then the actual import statements would be in a form: import "github.com/user/project1/utils" This is because go install works with git repositories. It is possible to use relative file-system-based paths as suggested in the answer, but, this would only work locally, and the project would not be able to be shared with others. – marni Oct 26 '18 at 22:07
62

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

enter image description here

Jossef Harush Kadouri
  • 32,361
  • 10
  • 130
  • 129
marni
  • 4,214
  • 1
  • 24
  • 18
  • 4
    First of all, thanks for pointing out this important update! One minor nitpick: "the idiomatic way to do relative imports in your project tree would be […]" – What you're describing are still *absolute* imports, not relative imports. In fact, according to the GitHub issue that's mentioned in the FAQ you linked to, relative imports *were* possible before but apparently are no longer. – balu Nov 20 '18 at 15:18
  • 1
    I guess it depends on how one defines "absolute" and "relative". I meant "relative" in a sense of existing ONLY within your current project. Existing relative to your current project module name, only. Not in any public Git repo; Not in the central module storage on your system. Not visible outside your current, in-the-filesystem, codebase. If you mean "relative" as in "relative in a filesystem-way with ../../ like notation" then yes, you are right. This might not qualify as "relative" in that sense of the word. – marni Apr 30 '19 at 09:54
  • 2
    Relative means without depending on an external name or config such as "m" - something that would work purely based on the relative directory structure and nothing else. In that sense, this is not relative. – CppNoob Sep 25 '19 at 17:11
21

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())
}
hjpotter92
  • 78,589
  • 36
  • 144
  • 183
Thomas S.
  • 5,804
  • 5
  • 37
  • 72
  • 1
    It would be `"mycompany.com/mytest/test1/utils"` instead of `"mycompany.com/test1/utils"`, rest everything is perfect. – Neeraj Sewani Mar 05 '21 at 11:10
  • This also works between 2 subdirs. Say there is another sub folder called common with a file db.go. utils/texts.go can reference exported members in common/db.go using import "mycompany.com/mytest/test1/common" – Paul P M Nov 30 '22 at 04:59
3

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.

snath03
  • 95
  • 7
hdante
  • 7,685
  • 3
  • 31
  • 36
  • Wow, it really works, I always thought this was not possible (and for good reason). Interesting though. Thanks! – VinGarcia Nov 04 '21 at 15:23
  • I tried this in goland, and it says `Cannot resolve symbol` for the relative package. – Eric Nov 28 '21 at 06:18
2

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.

rodmanb
  • 101
  • 7
1

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/.

nnnn20430
  • 155
  • 1
  • 4
0

Suppose this is the directory

-calculations --> add.go

-main.go

Create a go.mod file in the root directory and enter the following:

module calculator
go 1.14

Then in main.go

import (
  "calculator/calculations"
  "fmt"
)
func main() {
fmt.Println(calculations.Add(5,9))

}

In add.go

package calculations
func Add(int x, int y) int {
return x+y
}