Hello, World!¶
Let’s start out with a Hello World example. Our program will greet the world with a hello and the current time.
In Python it looks something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #!/usr/bin/env python
import time
def greeting():
'''Returns a pleasant, semi-useful greeting.'''
return "Hello world, the time is: " + time.ctime()
def main():
print greeting()
if __name__ == '__main__':
main()
|
It’s not that different in Go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // A "Hello World" program that prints a greeting with the current time.
package main
import (
"fmt"
"time"
)
// greeting returns a pleasant, semi-useful greeting.
func greeting() string {
return "Hello world, the time is: " + time.Now().String()
}
func main() {
fmt.Println(greeting())
}
|
Curly Braces¶
The first thing one may notice is that whereas Python uses whitespace to denote
scope, Go uses curly braces. The Go authors did, however, take a lesson from
Python’s culture of readable code. Although it is certainly possible to write
syntactically valid Go code without any indentation at all, nevertheless almost
all Go code one sees is formatted consistently and readably. That’s because,
Go includes a code formatter along with the compiler. The formatter, gofmt
,
is considered canonically correct by the Go community - if you don’t like how
gofmt
formats your code, you are wrong. It is customary that gofmt
always be run before checking in code.
$ gofmt -w hello.go # -w option updates the file(s) in place
Package¶
In any .go
file, the first non-comment line is a package
declaration.
The package declaration is mandatory - every .go
file must begin with one.
Every .go
file in the same folder must have the same package name.
The package
declaration is preceded by a comment, called the package
comment. Automatic documentation tools like godoc
extract the package
comment as the description of your program.
// A "Hello World" program that prints a greeting with the current time.
package main
Import¶
Next comes the import
declaration. Although it is optional, most .go
files will have one. Each package to be imported is listed on a separate line,
inside quotation marks. The packages in our example, fmt
and time
, come
from the standard library. By convention, 3rd-party packages are named after
their repository URL. For example, my Neo4j library hosted on Github would be
imported as "github.com/jmcvetta/neo4j"
.
import (
"fmt"
"time"
)
Functions¶
Our program has two functions, greeting()
and main()
.
The function greeting()
takes no arguments, and returns a string. Unlike
Java and C, in Go the type declaration follows the function name. Like all
good function declarations, this one includes a doc comment describing what it
does.
// greeting returns a pleasant, semi-useful greeting.
func greeting() string {
Return¶
Every function that declares a return type, must end with a return
statement. In this case we add a literal string to the output of
time.Now().String()
Let’s look at the documentatation for time
. We can see that time.Now()
returns an instance of type Time
. That instance, in turn, exports a
String()
method that unsurprisingly returns a string
. Using the
addition operator with two strings results in the strings being concatenated.
If we had tried to add our greeting string to just time.Now()
the code would
not compile, due to type mismatch.
$ godoc time Now String
PACKAGE DOCUMENTATION
package time
import "time"
[ ... ]
type Time struct {
// contains filtered or unexported fields
}
A Time represents an instant in time with nanosecond precision.
Programs using times should typically store and pass them as values, not
pointers. That is, time variables and struct fields should be of type
time.Time, not *time.Time. A Time value can be used by multiple
goroutines simultaneously.
Time instants can be compared using the Before, After, and Equal
methods. The Sub method subtracts two instants, producing a Duration.
The Add method adds a Time and a Duration, producing a Time.
The zero value of type Time is January 1, year 1, 00:00:00.000000000
UTC. As this time is unlikely to come up in practice, the IsZero method
gives a simple way of detecting a time that has not been initialized
explicitly.
Each Time has associated with it a Location, consulted when computing
the presentation form of the time, such as in the Format, Hour, and Year
methods. The methods Local, UTC, and In return a Time with a specific
location. Changing the location in this way changes only the
presentation; it does not change the instant in time being denoted and
therefore does not affect the computations described in earlier
paragraphs.
func Now() Time
Now returns the current local time.
func (t Time) String() string
String returns the time formatted using the format string
"2006-01-02 15:04:05.999999999 -0700 MST"
[ ... ]
Variables¶
Python is dynamically typed. That means there is no difference between variable
assignment and declaration. For example, saying x = 3
is equally valid if
x
was previously undeclared, or if it was already declared as an integer, or
even if it was already declared as e.g. a string.
Go, on the other hand, is statically typed. A variable must be declared as a
specific type before a value can be assigned to it. Once declared, a variable
may only be assigned values of its declared type. Go also provides an operator,
:=
, that combined declaration and assignment in the same statement.
Let’s look at a needlessly complex version of our greeting function to see how variable declaration and assignment work.
1 2 3 4 5 6 7 8 9 | // needlesslyComplexGreeting uses needlessly complex operations to return a
// pleasant, semi-useful greeting.
func needlesslyComplexGreeting() string {
var now string
now = time.Now().String()
msg := "Hello world, the time is: "
msg += now
return msg
}
|
On line 4 we used the var
keyword to declare the variable now
as a
string. It is initially set to the zero value for string
type, which is
“” the empty string. Line 5 assigns the (string) return value of
time.Now().String()
to now
.
On line 6 we use the short variable declaration syntax to declare msg
as
a string
, and immediately assign it the value of a literal string. The
resulting variable is exactly the same as if we had declared it as var msg
string
on a seperate line.
Line 7 appends the value of now
to the value of msg
, working in this
case exactly like Python’s +=
operator. However unlike Python, only
strings can be added to other strings, no automatic type coercion is ever
attempted.
main()
¶
Our Hello World program declares its package as main
, and contains a special
function main()
. That tells Go to compile this code as an executable
program, with the entry point at main()
. The function main()
has no
arguments and no return value. Command line arguments - called “argv” in many
languages - are available from the standard library, either raw from
os.Args
, or with higher level abstraction from the package flag
.
Compiling¶
Python is an interpretted language - our program can be run immediately with the
python
command:
$ python hello.py
Hello world, the time is: Sat Jul 13 12:49:14 2013
Go on the other hand is a compiled language - our source code must first be
compiled into an executable binary before we can run it. We will use the go
command line tool to access the compiler.
go run
¶
As a convenience, the go
tool provides a run
command that first compiles
the specified file(s), then executes the resulting binary. Given Go’s
lightning-quick compile times, using go run
can feel similar to working with
an interpretted language like Python or Ruby.
$ go run hello.go
Hello world, the time is: 2013-07-13 13:01:23.837155926 -0700 PDT
Only programs that declare package main
– in other words, those which can
be compiled into an executable application – can be run with go run
. Note
that all files to be compiled must be specified on the command line, even tho
they are all declared as part of the same package.
Running code with go run
does not leave an executable binary file laying
around - it is deleted immediately after it is run.
go build
¶
We can use the go build
command to compile our code into an executable
binary. The binary is statically linked, and can be redistributed (on the same
platform) just by copying it, with no dependencies. The binary file is created
in the same folder that contains the source code.
$ ls
hello.go
$ go build -v .
hello
$ ls
hello* hello.go
$ ./hello
Hello world, the time is: 2013-07-13 13:07:57.150564433 -0700 PDT
go install
¶
The go install
command works like go build
, except instead of putting
the binary file in the source code folder, it installs it to
$GOPATH/bin
. If $GOPATH/bin
is on your $PATH
, your program will be
available as a command after running go install
.
$ ls
hello.go
$ go install -v .
hello
$ ls
hello.go
$ ls $GOPATH/bin
hello*