For the past year I’ve been working with two programming languages: Ruby and Javascript. I’ve been wanting to branch out a bit and learn another language that’s different from both of those, so I decided to try working with Go. Ruby and Javascript are both dynamically typed languages, whereas Go is a statically typed, compiled language.

My next few blog posts will go into detail on the Go project I will be building, but before I get going with Go (lol) I’d like to take some time to digest a few Go basics. The information below was learned from the tutorials in the Go Documentation, available at golang.org.

Structure

Briefly, Go modules are the largest structures, which contain packages that contain your Go code. The modules define the environment for their packages, specifying the Go version required and any other modules referenced within their packages. This information can be found within the go.mod file for your module.

Packages

Each package within a module (and file within the package) declares itself at the top of the file and contains any necessary package imports and the Go code. Your program is run through the main package. The below example shows an example package that imports the “fmt” package and uses it in the HelloWorld function.

For example:

package example

import (
  "fmt"
)

func HelloWorld() {
  fmt.Println("Hello World!")
}

The function “HelloWorld” is a function that can be imported into other functions. In Go, exportable functions are named with capitalized letters. If “HelloWorld” was “helloWorld” it would only be visible within the example package.

Functions

Unlike Ruby and other object oriented programming languages, Go has no classes. Functions in Go are first-class-citizens. They can take multiple arguments. Because Go is a statically typed language, the type of each parameter needs to be included with it’s name. Types come after the name. If your function returns something, the type of the return value is noted after the parameters list.

func myName(name string) string {
  return name
}

Variables

Variables are declared with their type. They can be declared at the package or function level. They can be declared with var (constants can be declared with const) but variables can be declared at initialization with := instead of var. They can also be declared with an intializer but without a type and the variable will take the type of the initializer. Outside of functions, each statement must begin with a keyword, such as var, func or const.

var num, sum int

var x, y int = 2, 3

var s, t = 4, 5

c := true

Variable types can be changed, but this must be done explicitly with an expression formatted T(i). For example, the int 4 can be converted to a string with the expression string(4).

Other Syntax

Go only has a for loop – no while loops. The for loop can be written with an intial statement, the condition for looping, and a post statement for after each iteration. For loops can omit the initial and post statements and used similar to while loops. The for loop statements are separated with semicolons and the code after is wrapped in curly braces.

If statements are written similarly, with a conditional statement that is followed by code wrapped in curly braces. You can include an initial statement before the conditional, but any variable declared there is only accessible within the if statment (and its else blocks, if present).

Pointers hold the memory address of a value and Go uses pointers. Pointers are referenced with the *. They can be indirectly referenced through other variables by tying them with an &.

var p *int

i := 42
p = &i

fmt.Println(*p) // see i through pointer p
*p = 21         // set i through pointer p

Structs in Go are a collection of attributes with their types. Their fields can be accessed with a dot ([struct name].[field name]) and set with [Field Name]: [value].

type Name struct {
  first, last string
}

var (
  me = Name{"Sarah", "Rose"}    // me.first set to "Sarah" me.last: "Rose"
  friend = Name{}               // first and last set implicitly to empty strings
  relative = Name{first: "Sue"} // first set explicitly, last implicitly
)

In Go, arrays are set with types and length. They cannot be resized, but slices are dynamically-sized, providing a nice workaround. Slices don’t store data – they are references to a section of an array and are written a[low:high]. If you change an element in a slice, it changes the original array. When slicing from an array you may omit the low or high values (or both) if using the defaults. You can create a slice directly with a pair of empty brackets followed by the type.

I hope this brief overview of a few Go basics was helpful! I know I’ll be referring to it frequently as I keep practicing…

Resource:

Go Documentation