Learning Resources for Software Engineering Students »
Author(s): Cara Leong
Reviewers: Darren Wee, Tran Tien Dat
Go (also known as golang
) is a compiled, statically-typed, garbage-collected language that has special memory safety and concurrent programming features. Born out of frustration with the available languages (e.g. C, C++, Java) and
environments for systems programming, Go was conceptualized by programmers at Google who sought to create a single language that was efficient to write, build and execute. Go also
supports newer developments in computing such as multicore processors and network systems.
Go is a language built for software engineers. As it was written by software engineers at Google, Go addresses and attempts to solve some of the pain points that exist in many commonly-used languages. For instance, the language has easy dependency management, prides itself on fast builds and has many easy to use debugging, testing, and code-vetting tools. These features make Go an easy language to use for software development.
Go is a useful systems-side (i.e. backend) language. As it was built with large, distributed architectures in mind, Go is useful for creating scalable server-side programs that handle multicore processors, networked systems or even large computation clusters. In other words, if you're looking to make an Android application, Go is probably not the language for you. However, if you're looking to pick up a language that is reasonably easy to learn, builds on the foundations of other common languages and creates programs that are easily scalable, then Go may be the language for you.
Go is an open source project. Learning about Go and contributing to the language may be a useful experience for those interested. In addition, its source code may be useful reading for those interested in learning good practices, or simply to find out more about how the language was implemented.
Of course, Go is not a perfect language. However, for some people, Go may be exactly the right language to pick up! If you're unconvinced about how you can learn and use Go, you can use the Go playground to write, build and execute code without installing Go on your machine.
As it builds on the foundations set by many popular and widely-used languages such as C, C++, Java and Python, much of Go's syntax draws from existing implementations and will be familiar to programmers looking to learn an additional language. However, Go also diverges explicitly from these other languages. Listed below are some features that make Go unique!
One immediately obvious difference between Go and other languages is that Go declares its variables in the format var variableName (variableType)
, with the variable's type declared to the right of the variable name, as follows:
var name string
name = "John Smith"
This differs from many other languages, which put the variable type to the left of the variable name.
In addition, the verbosity of a declaration statement in Go can vary. You do not need to declare the variableType
of a new variable if you use an initializer, as the type of the variable will be inferred from its initialization.
For instance, in the following example, the string
type is optional:
var name string = "John Smith"
// alternatively
var name = "John Smith"
In addition to omitting the type when it can be inferred, you can also eliminate the keyword var
when performing variable declaration by using the :=
short assignment statement. :=
acts as a shortcut to
declare and immediately initialize a variable inside of a function.
name := "John Smith"
Thus, we see that there are several potential ways to declare a variable in Go. Choosing which style of variable declaration to use depends on how verbose a programmer wants to be in declaring the variable. However, the upshot of having many different degrees of verbosity is that common problems of both dynamically- and statically-typed languages can be avoided. Unlikely dynamically-typed languages, in which the type of a variable is sometimes unclear, a type in Go can always be explicitly declared to increase code clarity. On the other hand, when a variable's type can be clearly inferred, programmers can choose not to be unnecessarily verbose in their code.
Go's syntax for more complex types such as pointers, arrays and structs is also somewhat idiosyncratic, and can be explored in this Go blog article, or with the help of this tutorial on pointers and this tutorial on structs.
One of Go's special features is its focus on implementing concurrency simply and well. To this end, Go's standard library comes with two features that allow for easy and maintainable concurrency.
A goroutine is a lightweight thread that executes a function concurrently with its caller. A goroutine is launched by a go
statement:
func run() {
// does something
}
func main() {
go run()
executeOtherCommands()
}
In the above example, using the go
keyword launches a goroutine, which executes run()
concurrently with executeOtherCommands()
.
Goroutines can also be started for anonymous functions:
func foo() {
go func(msg string) {
fmt.Println(msg)
}("a message") // starts a goroutine that prints "a message"
}
A goroutine is not its own thread; instead, goroutines are dynamically multiplexed onto threads as required to keep them running. In addition, goroutines start with very small stacks which makes them lightweight, so having a large number of goroutines is feasible. In practice, goroutines behave similarly to very cheap threads.
Channels are used to fulfill Go's philosophy on concurrent software: "don't communicate by sharing memory; share memory by communicating". In other words, Go relies on message passing between concurrently running goroutines to share information.
Specifically, Go relies on channels to implement message passing. Channels are typed conduits that allows goroutines to communicate with each other by sending and receiving messages. Before using a channel of a specific type, we must declare
and make
it:
var c chan int
c = make(chan int)
//alternatively
c := make(chan int)
Channels can transmit data of any type; thus, creating a channel that transmits channels (i.e. a chan chan
) is theoretically possible and may even be useful.
Goroutines send and receive messages through a channel using the <-
2="" operator.="" go="" ch="" <-="" v="" Send="" to="" channel="" ch.="" :="<-ch" Receive="" from="" ch,="" and="" assign="" value="" v.=""
=""
One="" useful="" way="" think="" about="" sending="" receiving="" data="" with="" the="" <-
="" operator=""
is="" that="" moves="" in="" direction="" of="" arrow.="" Channels="" can="" be="" used="" synchronize="" execution=""
across="" goroutines,="" since="" receivers="" block="" until="" they="" receive="" data,="" while="" senders="" [until=""
receiver="" or="" buffer="" receives="" data](https:="" golang.org="" doc="" effective_go.html#channels).="" In="" code="" example=""
below,="" main
="" goroutine="" waits="" it="" a="" message="" worker
="" done="" before="" terminating.=""
func="" worker(done="" chan="" bool)="" {="" fmt.Print("Working...")="" time.Sleep(time.Second)="" fmt.Println("Done="" working")=""
true="" }="" main()="" go="" worker(done)="" <-done="" fmt.Println("Returned work") If you are interested delving deeper into using Go's concurrency features extensively,
Google developers have put out video presentations on [basic](https:
www.youtube.com watch?v="f6kdp27TYZs)" [advanced patterns](https: This [code walkthrough](https: codewalk sharemem ) provides an annotated how memory-sharing principles applied practice. ### Benefit:
Better Error Handling handling Go performed multiple returns. On any function fail, function's last return type should always error
. For example, os.Open
returns non-nil error when fails open file. Open(name string)
(file
File, err error) An error
variable represents describe itself as string, by implementing following interface: interface Error() string When calling method may error, we check if err !="nil
" handle resulting error. useFile() f, log.Fatal(err) do something File f use for errors [contrasted exceptions language like Java](https: davidnix.io post error-handling-in-go ). Unlike exceptions, which crash program, seen regular values expected programmers handled accordingly. To deal unexpected errors, also two mechanisms: panic
recover
. - similar throwing exception other languages. explicit call F
stops ordinary flow at point panic, executes functions deferred F
, F
's caller. caller, behaves panic. It triggers recursively propagates up stack all returned, after program crashes. fail fast cannot gracefully. recover
regains control panicking goroutine. Using comparable catching C++ Java. inside function, recover captures returned resumes normal execution. More information found [Go blog](https: blog.golang.org error-handling-and-go) wiki](https: github.com golang wiki PanicAndRecover). defer
Execution As opposed traditional mechanisms such if
, for
switch
, execute immediately, keyword pushes list, only list surrounding adds print functions. After foo
finishes executing, executed last-in-first-out order. foo() defer fmt.Println("This gets printed third") second") first") frequently clean-up actions, [close files](https: gobyexample.com defer). Deferred run panicking goroutines well, makes them recovering panic
. Good Support Interfaces Although has types methods allows pseudo-object-oriented style programming, hierarchy does not exist Go. Instead, uses interfaces specify implement, favouring composition over inheritance. Types need explicitly implemented. implement interface. Rectangle
implements TwoDimensional
area()
perim()
specified Thus, instances arguments price
. Meanwhile, although Circle
perim()
, area()
. Since interface, TwoDimensional
. TwoDimensional area() float64 perim() Rectangle struct width, height Circle radius (r Rectangle) r.width * r.height r.width2
+ r.height2 (c Circle) math.Pi c.radius price(t TwoDimensional) t.area() 3.5 main(){ c fmt.Println(price(c)) checks satisfy required compile time. above specifies satisfies actuality not. try your will get compile-time drawing attention
problem. (type argument price: (missing area method) benefit system where implementations stated source attached didn't write. words, extend without access its simply interface's own code. Some resources started include [this blog post](https:
medium.com golangspec interfaces-in-go-part-i-4ae53a97479c) introducing examples [how (including empty interface) practice](https: www.calhoun.io how-do-interfaces-work-in-go
more extensive look object-oriented programming Go, refer this [comparison OOP languages](https: flaviocopes.com golang-is-go-object-oriented ), [Go's official FAQ OOP](https: faq#Is_Go_an_object-oriented_language),
[tutorial Go](https: code.tutsplus.com tutorials lets-go-object-oriented-programming-in-golang--cms-26540). Canonical Coding Style Formatting enforced running go fmt
, align language-wide
standard indentation vertical alignment. given code: T name object int Running $ fmt
same directory file line comments correct code's indentation: Variations use, documentation](https: cmd gofmt enforces good coding practices,
instance, refusing build projects declare unused variables imports. Such enforcement, along clear, unified [treatise conventions effective_go.html), manifested reasonably stable style. ## How Get Started Go? [installation guide](https: install)
interactive [ tour tour.golang.org These highly comprehensive looking learn syntax those who prefer read existing examples, Example](https: collection samples covering wide variety includes line-by-line
explanations quick course syntax, Learn X Y Minutes cheatsheet](https: learnxinyminutes.com docs starting point. Where Here? development team heavily involved documenting growing community. keen here
some help started: [The FAQ](https: faq) answers common questions language's history, usage, design point, contains links Blog](https: news in-depth articles guests < br></-done="">