Skip to content

Latest commit

 

History

History
142 lines (107 loc) · 6.67 KB

2.02.md

File metadata and controls

142 lines (107 loc) · 6.67 KB

2.02 Hello World

Let's take a look at how a Go program works. We'll use The Go Playground for this. You need to have a package main inside of your program. Inside package main, you will have func main and func main is where your program runs. It can do lots of things, but func main is the entrypoint to your program, and also the exitpoint of your program. So when you leave func main() your program is over.

package main

import (
  "fmt"
)

func main() {
  fmt.Println("Hello, playground")
}

So, you need package main and that is a keyword. How would you know that is a keyword? You can check the Golang Spec. Go to the language specification, and check out Lexical Elements where you can see the Keywords. There aren't that many

break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var

But you can see package, import, and func

So, to reiterate, we have our package declaration; in this case package main. We have are importing the "fmt" package from the standard Go library, and then in our func main() we are calling the Println function from the fmt package.

Often we will import other packages from the standard library, or from third parties. You can write the import as a one-liner, i.e.

import "fmt"

When we are importing multiple packages, it's more idiomatic to use parentheses:

import (
  "fmt"
)

If I want to read the documentation about a Go package, in this case the fmt package, I can go to golang.org, click on documents scroll down to package documentation, then scroll down to fmt. You can also go to godoc.org, ior in this case godoc.org/fmt. Some other examples are [godoc.org/het/http)(http://godoc.org/net/http), godoc.og/html/template, etc.

OK, so we're looking at the godoc.org/fmt documentation. If we look down, you can see the index. This is often the first place I go. Everything with a capital first letter is exported from the package, or it's visible from outside the package.

We don't say public/private in Go. Those words come with baggage from other languages. We say Exported/Not Exported, Visible/Not Visible outside the package. If it starts with a capital letter, that means it's visible outside the package.

We're using fmt.Println from the fmt package. Let's look at the documentation for fmt.Println.

func Println(a ...interface{}) (n int, err error)

"Println formats using the default formats for its operands and writes to standard output. Spaces are always added between operands and a newline is appended. It returns the number of bytes written and any write error encountered."

Generally speaking in Go, you're always going to do something with a returns, but sometimes you don't have to, and what the rule is for when you do and when you don't, I'm not totally clear. With Println, I've always seen it used without capturing the int and the err.

If we wanted to catch the int and the err, we could say

package main

import (
	"fmt"
)

func main() {
	n, err := fmt.Println("Hello, playground")
	fmt.Println(n, err)
}

but then you might think, now we have to do something with what is returned, so

package main

import (
	"fmt"
)

func main() {
	n, err := fmt.Println("Hello, playground")
	n2, err2 := fmt.Println(n, err)
}

which is probably why we don't usually see capturing the int and the err, because it could lead to an infinite loop of capturing errors.

Another way you can get rid of things which are being returned, is you can just throw them into the void. Go is all about not wasting effort and having clean code.

One of the ways to avoid code pollution is to not have variables that you do not use. So in this case, if we say we have n2, and err2, but we're not using it, and try running it, it will throw an error.

package main

import (
	"fmt"
)

func main() {
	n, err := fmt.Println("Hello, playground")
	_, _ := fmt.Println(n, err)
}		

This says tmp/sandbox214796246/main.go:9: no new variables on left side of := Which is saying we're not declaring new variables on line 9, so we can just use the equals sign (we'll learn about the short declaration in a moment), and it compiles and runs.

package main

import (
	"fmt"
)

func main() {
	n, err := fmt.Println("Hello, playground")
	_, _ = fmt.Println(n, err)
}		

This prints out

Hello, playground
18 <nil>

This printed out "Hello, playground" and it printed out my n, with is the number of bytes (18) and the err, which is nil.

To recap, from package fmt we have used the Println function. This takes a variadic parameter of any type. We'll learn about interfaces later on. When you see the triple dots and then the type, that means you can take an unlimited number of this type. This type right here interface{} is the empty interface. Everything implements the empty interface, so you can put as many values as you want in here and just separate them by commas, and fmt.Println will just print them out.

So, if we wanted to, we could keep adding more variables

package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello, playground", 42, "something else", true)
}

and it will keep printing them out.

So that is Println from the package fmt. We had some exposure to reading documentation. The main take away you should get from this video is that every program in go starts in package main, and it starts in func main. So package main needs to have func main.

func main is the entrypoint to your program, and when it exists your program is over. We use this dot notation where we have package.Identifier The identifier can be for a variable, a constant, or a function. Any identifier for a variable, constant or function that starts with a capital is exported or visible from outside the package. Println starts with a capital, so we can access that. This takes a variadic parameter, which is the triple dots, and that just means it can accept any number of arguments, in this case of type of an emtpy interface interface{}, which can be any type. We comma separate them.

We will look at format printing in the next video.