Directory Structure and Import - go

I do not understand how the package / project directory structure works.
I am following these 2 links enter link description here and enter link description here
My Go workspace is located under /workspace/golang.
My $GOPATH is equal to /workspace/golang
My directory structure is as follow :
/workspace/golang/src/Tutorial/
...tutorial_main.go <- Default 'Hello World' program
...library/
......arithmetic.go
Content of arithmetic.go :
package library
func addNum(a int, b int) int {
return a + b
}
I cd into library folder and ran go build arithmetic
Now, I cannot figure out how to use my arithmetic.go in my tutorial_main.go file.
I tried the following :
import "library"
fmt.Println("Result : ", library.addNum(1,4))
import "Tutorial/library"
fmt.Println("Result : ", library.addNum(1,4))
import "src/Tutorial/library"
fmt.Println("Result : ", library.addNum(1,4))
Neither works.
It keep saying it cannot find library
I don't understand what I am doing wrong.

With your setup, the package import path is:
import "Tutorial/library"
And you should capitalize the names you want to export in the library package so you can access them from other packages.
In general, the import path is the file path of the package (relative to $GOPATH) if it is local, or the remote path of the package, such as github.com/myaccount/package. The simple import names such as import library are reserved for built-in packages. Relative import paths also work, but they are not recommended, i.e. import ./library.
That said, with the module system $GOPATH is no longer used. I recommend you read modules and how you can work outside the $GOPATH.

In Go, your variables and functions that you'd like to export (make available outside your package) need to start with a capital letter.
package library
func privateAddNum(a int, b int) int {
return a + b
}
func PublicAddNum(a int, b int) int {
return a + b
}
privateAddNum is an unexported function and will only be accessible within the library package.
PublicAddNum is an exported function and will be accessible to external packages that import library.

Related

(import path does not begin with hostname)

My demo golang project is https://github.com/aQuaYi/demoGolangProjectWithCI
demoGolangProjectWithCI/subModel/subModelAdd.go is
package subModel
import (
"demoGolangProjectWithCI"
)
//Add returns sum of a and b
func Add(a, b int) int {
return demoGolangProjectWithCI.Add(a, b)
}
and my .travis.yml is
language: go
go:
- 1.8.3
script: go test ./...
but travis said me "package demoGolangProjectWithCI: unrecognized import path "demoGolangProjectWithCI" (import path does not begin with hostname)"
detail is https://travis-ci.org/aQuaYi/demoGolangProjectWithCI/builds/247416861
How Could I fix this?
Thank you very much.
demoGolangProjectWithCI is not resolved from subModel because import "demoGolangProjectWithCI" mean absolute path. You can write relative path like ./demoGolangProjectWithCI. But, in generally, you've better to write full-github-paths as github.com/aQuaYi/demoGolangProject since your package may be used by other one's project.

How to export a name so that it becomes globally accessible?

I want to export a function from my package so that I can use it without typing a package name before it, how to do that?
import "mypackage"
func main() {
mypackage.myfunc() <-- that's what I have already
myfunc() <-- that's what I need
}
You can use one of the followings:
import (
. "mypackage" // without a name
mp "my/other/package" // rename
_ "my/totally/diffrent/package" // import a package solely for its side-effects (initialization)
)
Obviously, this pattern is not recommended since it can cause name conflicts with other packages.
Check out the dot imports bulletin

How to specify the package name if multiple files exist in the package folder and one file contains the "package main"?

Suppose I have a package folder as below:
hello
|---main.go
|---utilities.go
In the main.go, I have:
package main
In the utilities.go, I have:
package hello
I did this because:
I don't want to put all the utilities into the single main.go file.
And the utilities are only used by this package so I don't want to put it out of the hello folder.
But when I run go list hello, it gives me this:
can't load package: package hello: found packages main (main.go) and
hello (utilities.go) in E:\Workbench\Go\src\hello
Then I remove the utilities.go and tried the go list hello again with only main.go. It gives me this:
hello
So do I have to move all the utilities to another package folder?
Do I have to keep only the single main.go in the hello package folder because it seems it doesn't get along well with other package names?
ADD 1
An useful ref: http://thenewstack.io/understanding-golang-packages/
ADD 2
After a few brief experiments, I guess the import yyy decides the link search path while the package xxx declaration decides the exported symbol name in the compiled .a file.
Because I noticed these facts:
The package xxx declaration doesn't have to be the same as the containing package folder name, say yyy.
But the import yyy declaration must use the package folder path yyy.
When using a symbol from a package, we must still use the xxx.Symbol rather than yyy.Symbol.
ADD 3
To confirm my guess in ADD 2, I did this:
(pkg1\file1.go)
package pkg2 // I deliberately use a different pkg name "pkg2" rather than the folder name "pkg1"
import "fmt"
func FA() {
fmt.Println("in the pkg2.FA")
}
(cmd1\main.go)
package main
import "pkg1"
func main() {
pkg2.FA() //here, the FA is referenced via "pkg2" rather than the "pkg1".
}
The above 2 files can compile and run.
But if I changed to this:
(cmd1\main.go)
package main
import "pkg1"
func main() {
pkg1.FA() //here, the FA is referenced via "pkg1" as in the import statement. Should work, isn't it?
}
This will give:
....\src\cmd1\main.go:3: imported and not used: "pkg1" as pkg2
....\src\cmd1\main.go:6: undefined: pkg1 in pkg1.FA
And to double confirm, I checked the compiled pkg1.a file with go tool nm pkg1.a, I didn't see package name affects the exported symbols. (btw, the GNU nm tool seems not be able to recognize the golang .a file format.)
U
515 T %22%22.FA <========== this is my fuction FA
67b R %22%22.FA·f <========== this is my fuction FA
5eb T %22%22.init
67b B %22%22.initdone·
683 R %22%22.init·f
U fmt.Println
U fmt.init
673 R gclocals·33cdeccccebe80329f1fdbee7f5874cb
66b R gclocals·69c1753bd5f81501d95132d08af04464
65b R gclocals·e29b39dba2f7b47ee8f21f123fdd2633
64d R go.string."in the pkg2.FA"
63d R go.string.hdr."in the pkg2.FA"
7d2 R go.typelink.*[1]interface {}
796 R go.typelink.[1]interface {}
737 R go.typelink.[]interface {}
U runtime.algarray
U runtime.convT2E
6ec R runtime.gcbits.01
68b R runtime.gcbits.03
U runtime.morestack_noctxt
U runtime.throwinit
79a R type.*[1]interface {}
7d6 R type..importpath.fmt.
73b R type..namedata.*[1]interface {}.
6ed R type..namedata.*[]interface {}.
68c R type..namedata.*interface {}.
74e R type.[1]interface {}
6ff R type.[]interface {}
69c R type.interface {}
U type.string
So the conclusion so far is:
When the declared package name is different from the package folder name, package declaration will be used as an alternate name of the package.
Equivalent to this, but implicitly :
import pkg2 "pkg1"
And btw, since the package declaration is not reflected in the compiled .a file, I guess the golang compilation requires the presence of .go file.
go files in the same package AKA folder must have the same package name. The only exception are tests that can have a _test extension. The rule is 1 folder , 1 package therefore the same package name for all go files in the same folder.
The answer is yes , move the "hello" package files to their own folder or , use the same package name for all files in the same directory.

Is it possible don't specify package name?

Here is an example of my code:
package main
import (
"./bio"
)
func main() {
bio.PeptideEncoding(genome, codonTable)
}
Is it possible to use functions from my paxkage (bio) without specifying package name:
func main() {
PeptideEncoding(genome, codonTable)
}
?
You could use as an import declaration like:
. "./bio"
If an explicit period (.) appears instead of a name, all the package's exported identifiers declared in that package's package block will be declared in the importing source file's file block and must be accessed without a qualifier.
That is what a testing framework like govey does:
package package_name
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestIntegerStuff(t *testing.T) {
Convey("Given some integer with a starting value", t, func() {
x := 1
Convey("When the integer is incremented", func() {
x++
Convey("The value should be greater by one", func() {
So(x, ShouldEqual, 2)
})
})
})
}
You don't need to use convey.So(), or convey.Convey() because of the import starting with a '.'.
Don't abuse it though, since, as twotwotwo comments, The style guide discourages it outside of tests.
Except for this one case, do not use import . in your programs.
It makes the programs much harder to read because it is unclear whether a name like Quux is a top-level identifier in the current package or in an imported package.
That is why I mentioned a testing framework using this technique.
As commented by Simon Whitehead, using relative import is not generally considered as the best practice (see for instance "Go language package structure").
You should also import the package via the GOPATH instead of relatively, as show in "Import and not used error".

Call a function from another package in Go

I have two files main.go which is under package main, and another file with some functions in the package called functions.
My question is: How can I call a function from package main?
File 1: main.go (located in MyProj/main.go)
package main
import "fmt"
import "functions" // I dont have problem creating the reference here
func main(){
c:= functions.getValue() // <---- this is I want to do
}
File 2: functions.go (located in MyProj/functions/functions.go)
package functions
func getValue() string{
return "Hello from this another package"
}
You import the package by its import path, and reference all its exported symbols (those starting with a capital letter) through the package name, like so:
import "MyProj/functions"
functions.GetValue()
You should prefix your import in main.go with: MyProj, because, the directory the code resides in is a package name by default in Go whether you're calling it main or not. It will be named as MyProj.
package main just denotes that this file has an executable command which contains func main(). Then, you can run this code as: go run main.go. See here for more info.
You should rename your func getValue() in functions package to func GetValue(), because, only that way the func will be visible to other packages. See here for more info.
File 1: main.go (located in MyProj/main.go)
package main
import (
"fmt"
"MyProj/functions"
)
func main(){
fmt.Println(functions.GetValue())
}
File 2: functions.go (located in MyProj/functions/functions.go)
package functions
// `getValue` should be `GetValue` to be exposed to other packages.
// It should start with a capital letter.
func GetValue() string{
return "Hello from this another package"
}
Export function getValue by making 1st character of function name capital, GetValue
you can write
import(
functions "./functions"
)
func main(){
c:= functions.getValue() <-
}
If you write in gopath write this import functions "MyProj/functions" or if you are working with Docker
In Go packages, all identifiers will be exported to other packages if the first letter of the identifier name starts with an uppercase letter.
=> change getValue() to GetValue()
you need to create a go.mod file in the root directory of your project: go mod init module_name
the name of exposed function should start with capital letter
import(
"module_name/functions"
)
func main(){
functions.SomeFunction()
}

Resources