Package selection in Go - go

I'm trying to write an application to pull status from a database, but I seem to be getting stuck on a really basic principle of the language. I have the program written, but it doesn't compile due to the error use of package time not in selector.
A really basic example (from play.golang.org's own test environment)
package main
import (
"fmt"
"time"
)
func main() {
s_str := time.Now()
fmt.Println( printT(s_str) )
}
func printT(t time) time {
return t.Add(100)
}
Unfortunately, I've found documentation and helpdocs online a bit wanting. My understanding is that the import statement should include the library for the entire program like in C++ correct?

You have to prefix the imported types or variables with the name you gave to the package in the import (here you use the default name, that is "time"). That's what you did for the function Now but you have to do it also for the types.
So the type isn't time but time.Time (that is : the type Time that is declared in the package you import with the name "time").
Change your function to
func printT(t time.Time) time.Time {
return t.Add(100)
}
And for your second question : No, the import statement doesn't include the library for the entire program but only for the current file.

Related

Golang in vscode: auto-import package

Imagine I want to use strconv.Atoi, but I am lazy, and want to import it automatically.
package main
import (
"fmt"
)
func main() {
i, _ := Atoi|("123")
fmt.Println(i)
}
The pipe sign (|) shows where my cursor is
In PyCharm I was able to automatically import the matching function via alt+ENTER.
Is there a way that vscode changes above code to this one:
package main
import (
"fmt"
"strconv"
)
func main() {
i, _ := strconv.Atoi("123")
fmt.Println(i)
}
VSCode won't guess which package Atoi() is from, but if you tell it, the import will be added automatically.
So just type
i, _ := strconv.Atoi("123")
And hit CTRL+S to save, and the import will be added automatically.
You may also press CTRL+ALT+O which is a shortcut to Organize Imports.
This is a reasonable compromise in Go. As part of API design, exported identifiers are created that read well with the package name. For example the constructor function that creates an MD5 hasher is md5.New() (and not for example md5.NewMD5()), the one that creates an SHA1 hasher is sha1.New(). Just entering New() it's often too verbose, and giving the package name is required to give context to what you refer to.

modifying imported functions in go

I could override the builtin print() function's behavior by defining another print() in scope, as in https://play.golang.org/p/Y2ly31oXU67
Is it possible in go to alter the behavior on-the-fly of an imported function, say fmt.Println()?
If you want to 'alter' a builtin function, look at the very fine monkey patch utility https://github.com/bouk/monkey (And pay attention to the warnings, it's only really useful in test functions, and I for one reject any prod code that imports that package)
Import a different package with name "fmt" and implement whatever functions you need in that package. Here's an example:
File go.mod:
module test
File main.go
package main
import (
"test/fmt"
)
func main() {
fmt.Println("Hello, playground")
}
File fmt/fmt.go:
package fmt
import (
"fmt"
"log"
)
func Println(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
log.Printf(msg)
}
Run it on the playground.
The code in this answer does not modify the imported function as asked in the question.

How to use variable package selector in go

I'm following the Go tour, and still trying to learn the basics of the language. For the imported package time, is there a way to access its exports with a variable? E.g. time[day] instead of time.Saturday
Here's a more complete example
package main
import (
"fmt"
"time"
)
func main() {
day := "Thursday"
fmt.Printf("When's %v?", day)
today := time.Now().Weekday()
switch time[day] { // This is how I would do it in javascript
case today + 0:
fmt.Println("Today.")
default:
fmt.Println("Too far away.")
}
}
Also, what is the correct terminology for what I want to do? I'm having very little luck using Google
No, there's no way to reference exported variables from a package, which are stored on the stack, without explicitly referencing them using a data structure that you define that's built at runtime.
For example, you could do:
var days = map[string]time.Weekday{
"Monday": time.Monday,
"Tuesday": time.Tuesday,
"Wednesday": time.Wednesday,
"Thursday": time.Thursday,
"Friday": time.Friday,
"Saturday": time.Saturday,
"Sunday": time.Sunday,
}
fmt.Println(days["Thursday"])
See http://play.golang.org/p/6EYqcklf8X

Revel: "code does not compile: undefined: models"

I have created /app/models/todo-item.go file that looks like this:
package models
import (
"github.com/revel/revel"
)
type TodoItem struct {
Id int64 `db:"id" json:"id"`
Name string `db:"name" json:"name"`
}
func (b *TodoItem) Validate(v *revel.Validation) {
v.Check(b.Name,
revel.ValidRequired(),
revel.ValidMaxSize(25))
}
In src/RevelApp/app/controllers/init.go, I have this (PS, I am using GorpController to interact with MySQL):
func defineTodoItemTable(dbm *gorp.DbMap){
// set "id" as primary key and autoincrement
t := dbm.AddTable(models.TodoItem{}).SetKeys(true, "id")
t.ColMap("name").SetMaxSize(25)
}
I am getting an error :
The Go code src/RevelApp/app/controllers/init.go does not compile: undefined: models
I have tried importing ."RevelApp/app/models" then doing away with models in models.TodoItem{} (as describer here: Revel with Gorm "undefined: Page") and I get the error : App failed to start up
revel/harness: app timed out.
That link is the only one I could find related to this issue. Am I missing something?
EDIT: $GOPATH:
/home/me/Source/go
models location:
/home/me/Source/go/src/RevelApp/app/models
How I am importing models package:
import (
."RevelApp/app/models"
"github.com/revel/revel"
"github.com/coopernurse/gorp"
"database/sql"
_ "github.com/go-sql-driver/mysql"
"fmt"
"strings"
)
You have imported your models using the dot (.) import qualifier. From the language spec:
If an explicit period (.) appears instead of a name, all the package's exported identifiers will be declared in the current file's file block and can be accessed without a qualifier.
This means you don't need to use models.TodoItem .. you can simply use TodoItem.
That said .. I would suggest avoiding this and removing the dot from the import statement:
import (
"RevelApp/app/models"
"github.com/revel/revel"
"github.com/coopernurse/gorp"
"database/sql"
_ "github.com/go-sql-driver/mysql"
"fmt"
"strings"
)
Why? It stops your local file scope becoming crowded and allows you to see where each object actually resides.
For completeness (and you're probably wondering what its for since the dot is similar), that underscore (_) before the mysql package statement basically says "import this package .. but I don't need to use anything in it directly". This fires the packages init function allowing it to register itself with the database/sql packages routines. Which is why when you use the sql.DB type it is eventually routed to the MySql package code.

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

Resources