Is it possible a Golang package in subdir not included by default? - go

I am using a golang package, say name pkgfoo; and the author explicitly said if we want to use a package subpkg under pkgfoo, I need to explicitly import subpkg. I don't understand the reason behind it. Isn't the subpkg automatically imported if I import the top pkg in Golang?
package main
import (
"myownpackage"
"github.com/usera/pkgfoo"
"github.com/usera/pkgfoo/subpkg"
)
func main() {
// Use functions in pkgfoo, and use functions in pkgfoo/subpkg
// ......
http.HandleFunc("/login", login)
err := http.ListenAndServe(":9090", nil) // setting listening port
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
My question is whether I really need import "github.com/usera/pkgfoo/subpkg" statement.

Go packages are constructed from one or more source files, which are organized into folders in the file system. Source files of the same package must be in the same folder.
But in Go there is no "package hierarchy", the "subpackage" term simply refers to the folder of a package being a subfolder of another. We often organize packages to be in folders being subfolders of others because there is some connection between those packages (e.g. a package is used only by another being in the parent folder; or a package in a subfolder is a specific or more special implementation of the package in the parent folder; or simply just a logical grouping - see the end of the answer).
So whenever you do
import "github.com/usera/pkgfoo"
It only imports pkgfoo and no other packages sharing the same path as prefix. If you need github.com/usera/pkgfoo/subpkg too, you also need to explicitly import it:
import (
"github.com/usera/pkgfoo"
"github.com/usera/pkgfoo/subpkg"
}
The Go Blog: Package names on directories used in the standard library:
Directories. The standard library uses like directories crypto, container, encoding, and image to group packages for related protocols and algorithms. There is no actual relationship among the packages in one of these directories; a directory just provides a way to arrange the files. Any package can import any other package provided the import does not create a cycle.

Related

Unable to use functions within imported package

My current Directory is setup as follows:
-- /webserver
|
/ftp
|-> ftp.go
|-> go.mod
|->server.go
|->go.mod
Server.go page heading
package main
import (
[..]
"../webserver/ftp" // issue package
)
func main() {
[..]
ftp.test()
}
ftp.go page
package ftp
import "fmt"
func test() {
fmt.Println("YES!")
}
Here's the part I cant seem to understand in the console "PROMBLEMS" tab. The ftp.go file gets saved. Before I save the server.go file with "../webserver/ftp/" the console displays this:
When I save server.go it removes "./webserver/ftp", I went as far as adding it into the go src to make it "ftp" instead of "../webserver/ftp". I get the same result.
Not sure what I am doing wrong.
Basically what i want to accomplish is:
have a functions folder and have the functions in that folder (functions.go) to keep the server.go page as clean as possible.
You have several problems here.
ftp/go.mod should not exist. While it is possible to have multiple Go modules in a single repository, this is very advanced usage, and is rarely useful. Unless you absoultely know that you need this capability, and are already exremely comfortable with creating and publishing Go modules, don't do this.
Go does not support relative imports. import "../webserver/ftp" is an invalid import path*. Use the fully qualified import path, i.e. import "github.com/username/projectname/webserver/ftp"
The path to use here depends on the module name you've declared on the module line of your your top-level go.mod file.
You cannot import unexported values.
You've defined func test() string in ftp.go. This is unexported, by virtue of beginning with a lowercase letter. Only functions, variables, or other symbols which begin with a capital letter are exported in Go. Try func Test() string instead.
*Some will say "But I used import ".../foo" and it worked!". Yes, it can work under very specific circumstances. But its behavior is not reliable, so you should never rely on this, except in very specific testing types of situations.

Golang import cycle not allowed

I am creating a restful api in GO and every method essentially interacts with the database. The specific statement that I use to open a database connection is
db,err := sql.Open("postgres", "user=postgres password=password dbname=dbname sslmode=disable")
if err != nil {
log.Fatal(err)
println(err)
}
It is very simple but the issue is that once I want to change something inside that statement then I have to change it for all other methods that have that statement . I am trying to do a dependency injection or something of that nature so that I can have that statement or value in 1 place and just reference it. I am getting an import cycle not allowed error though like Import cycle not allowed . This is my project structure
What I have done is that in the Config.go I have written this
package Config
const Connect = "user=postgres password=password dbname=dbname sslmode=disable"
Then in the Listings.go I put this
package Controllers
import (
"net/http"
"database/sql"
"../Config"
)
func Listing_Expiration(w http.ResponseWriter, r *http.Request) {
db,err := sql.Open("postgres",Config.Connect)
if err != nil {
log.Fatal(err)
println(err)
}
notice I have the import ../Config and the Config.Connect but when I compile that I get import cycle not allowed . I have been trying to solve this issue but haven't been able to.
Yes, Go doesn't allow to have cycled imports. In your example you have 2 packages Config and Controllers. When you build a code, Controllers package requires Config package, then Config requires Controllers and it's endless. You should refactor your code to make Config package separated from Controllers, and only used by it. Also, you can make some common package, imported to Controllers and Config.
I got the same error. But in my case, I imported the package itself inside the file. so you can check if you did the same mistake.
Go does NOT allow import cycles. So you need to fix it. In your case, Controller and Config are importing each other, you are not allowed to do that.
I wrote a detailed blog about how you can deal with it. Refer https://jogendra.dev/import-cycles-in-golang-and-how-to-deal-with-them
Use interfaces.
Making use of go:linkname.
Though, I can't see any import cycle from your code.
Go don't support the import cycle. Based on your question, you must import the controller from the Config Package. You need to remove one of them and refactor your code.
Fore more: https://jogendra.dev/import-cycles-in-golang-and-how-to-deal-with-them

Using an External Dependency in a Library

I am using wgo for dependency management in Golang (although I think wgo has little to do with this), wgo has a folder structure like this
project/
.gocfg/
gopaths
vendor.json
vendor/
src/
github.com_or_whatever/
I have a library I coded myself which uses an nsq-go type in one of the exported methods:
func AddNsqSubscription(
topic, channel string,
handler nsq.Handler,
config *nsq.Config) error { }
The library is called messi and I import the nsq-go like so "messi/vendor/src/github.com/bitly/go-nsq"
The problem comes when I try to use this library in another project. For instance, in a project called scribe I have the following code (notice the imports):
import (
"scribe/vendor/src/github.com/bitly/go-nsq"
"scribe/vendor/src/messi"
)
//...
nsqHandler := nsq.HandlerFunc(func(message *nsq.Message) error {
msgHandler(MessiMessage{message})
return nil
})
return messi.AddNsqSubscription(destination, subdestination, nsqHandler, nsq.NewConfig())
When I go build the following error is returned:
cannot use nsqHandler (type "scribe/vendor/src/github.com/bitly/go-nsq".HandlerFunc) as type "messi/vendor/src/github.com/bitly/go-nsq".Handler in argument to messi.AddNsqSubscription:
"scribe/vendor/src/github.com/bitly/go-nsq".HandlerFunc does not implement "messi/vendor/src/github.com/bitly/go-nsq".Handler (wrong type for HandleMessage method)
have HandleMessage("scribe/vendor/src/github.com/bitly/go-nsq".Message) error
want HandleMessage("messi/vendor/src/github.com/bitly/go-nsq".Message) error
Why? I do not really know what is going on. The code go-nsq imported is exactly the same, yet golang wants that this code comes from the same folder?
What am I doing wrong?
Packages in Go are identified by full import path, not by name.
For example in the standard library there are two different packages with the same name template but different import paths: text/template and html/template.
You should make sure that go-nsq package is imported using the same path.

Package bound resource use for multiple go packages

For a contrived example:
I have 2 packages, repo.com/alpha/A & repo.net/beta/B. package A uses package B, both structured as example.
A:
main.go
B:
b.go
templates \
1.tmpl
2.tmpl
In main.go of package A, I'd need to access the templates directory of package B.
b.go
var templates string
templates = templatepath
func init(){
templatepath, _ = filepath.Abs("./templates")
}
main.go
import(
repo.net/beta/B
)
func main(){
fmt.Printf("%s", B.templates)
}
So the problem being in my more complex use case & the contrived example here is that B.templates will be in the directory for package A, where I need to establish and reference the directory of the imported path. This is part of learning and navigating the Go way of doing things, and my understanding is probably basic, so I need to understand how to do this in a Go context.
My use case is a package that uses other packages that do things for the base package, and these external packages may use standard web resources files(css, html, js) the problem being I'm having immediate trouble packaging and referencing them abstractly enough for what I want to do.
You can't, you have to either use something like go-bindata or so, or simply embed the templates in your B package as consts.
tmpl1.go:
const tmpl1 = `........`

In Go, how to import function directly, without need to prefix with the package name when I call it?

In the Go programming language, why after importing a package do I still have to prefix a method within that package with the package name?
i.e.
import "io/ioutil"
func main() {
content, err = iotuil.ReadFile("somefile.txt")
// etc..
}
Isn't this redundant? In Java, for example, you can do things like importing Files.readAllLines etc without having Files imported.
I guess this doesn't really answer your question, but if you want, you can actually call the methods without explicitly stating the package - just import with a . in front of the names (but this is not recommended; see below):
package main
import (
. "fmt"
. "io/ioutil"
)
func main () {
content, err := ReadFile("testfile")
if err != nil {
Println("Errors")
}
Println("My file:\n", string(content))
}
Note #jimt's comment below - this practice is not advised outside of tests as it could cause name conflicts with future releases. Also, definitely agree with #DavidGrayson's point of being nicer to read/see where things come from.
you can import and rename the package name, eg:
import (
. "fmt" // no name, import in scope
File "io/ioutil" // rename ioutil to File
_ "net" // net will not be available, but init() inside net package will be executed
)
See also https://golang.org/ref/spec#Import_declarations
I can't really speak for the designers of the Go language, but it is nice to be able to quickly tell where the method you are calling is defined. It is also nice to see a list of all the packages your are using at the top of the file. This is not redundant.
As you said, Java requires you to say Files.readAllLines and similarly go requires you to write ioutil.ReadFile.
Import statements in go are not like in java, more like #include in c++. In go, if something isn't imported, you can't use it. If it is imported, you can use it but must be prefixed with the package name. As everyone else said, use import . "packagename" to import a package and not have to prefix.

Resources