Introduction
Go, or Golang, is a statically typed programming language released by Google in 2009. It is a backend programming language, which I am using to build a web app. It has extensive built-in packages and features, as well as the capability of adding third party packages. Some of these include net/http, which includes the ability to listen on a port, route URLs and serve back content, html/template, which has the ability to create Go templates out of HTML pages and dynamically passed data, and database/sql, which provides the ability to connect to a database.
Using these packages, along with others, a developer can build a web app in Go.
Go has great documentation on the language and their packages, which I highly recommend checking out.
Below, I will demonstrate some of the abilities listed above, as well as some other interesting “quirks” about Go.
Structure
All files must begin with a package declaration in the first line.
To run a program, it will need a main function, like Java's main(String[] args)
method.
package main
func main() {
// contents of the main function here
}
Declarations
From a Java perspective, much of Golang can appear backwards. For example, in Java, declaration looks like:
Go is very strict when it come to the "use it or loose it" mentality. If a variable or import is declared but not used, it must be deleted, or it will not compile.
Speaking of declarations, here are some examples of common declarations in Go.
Now, developers can declare variables using the syntax above, but there are other ways.
// declare with type
var myString string
// declare with implied type
var myString = "Hello world"
This last one can only be used inside a block, such as a function.
// declare with ':='
myString := "Hello world"
Using Packages
To import a package, simply declare import()
, and list the imported packages in the parenthesis.
To use functions and variables, write the package name, followed by .
and the name of the thing you want.
// For example
import (
"fmt"
)
fmt.Print("Hello World!")
Remember, use it or loose it. The file will not compile with unused imports.
To import third-party packages as well as other local packages, you will need to create a go.mod file. In the command line, type go mod init {{project name}}
to create the go.mod file.
Loops
While languages such as Java and JavaScript have for, while, and do…while loops, Go has one: the for loop. It is very easy to work with, but there are multiple ways of using it:
// The basic for loop:
for i := 0; i < 10; i++ {
}
// The foreach loop (slices and arrays):
for index, item := range mySlice {
}
// The foreach loop (maps):
for key, value:= range myMap {
}
// The foreach loop (channels):
for input := range myChannel {
}
// The while true loop:
for isTrue {
}
// The infinite loop:
for {
}
Access
In Java, developers mark attributes and methods as private or public to control access. Go also allows developers to control access when exporting packages, but not with public or private, but with case. If a function or variable begins with an uppercase letter, it is public. Otherwise, it is private.
var privateString = "no one can see this"
var PublicString = "other packages can see this."
Objects (sort of)
Golang is not an Object Oriented Programming language, but it does allow for functionality similar to object creation. This can be done by declaring custom types, based on the struct, short for structure. Functions can even have receivers, making them like methods, the (u *User)
in this case.
With receivers, the function must be attached to a variable of the type defined in the receiver place (u *User)
. In the above example, one must declare a variable of type User and call the function from that.
var myUser User
myUser.WriteName
In the functionality, the receiver is referenced with the variable u
.
Arrays and Slices
We are all familiar with arrays. In languages like Java, the size of arrays are set, while in JavaScript, the size is dynamic. Golang has both. Arrays have a set length, which can not be changed. A slice is similar to an array, but it has variable length. They look very similar, but with one key difference: the value in the square brackets during declaration.
A developer can also return a slice from the contents of an array/slice using index values in square brackets, returning all elements from the first listed index to the last (exclusive). The absence of a starting index means start at 0, and the absence of an ending index means end at the last element (inclusive).
// return elements at indexes [2,5)
newSlice := myArray[2:5]
// return elements at 2 to the end
newSlice := myArray[2:]
// return elements from the start to 5 (exclusive)
newSlice := myArray[:5]
Random numbers
A big drawback of Golang is its random number generation. Using the math/rand package, there is a series of random value generators, but they all use the same seed, so the same numbers will be return in the same order each time. To combat this, the developer must add a seed of his own. To get a unique seed, developers use the current date in the time package, as that is always changing; thus, a different seed each time.
rand.NewSource(time.Now().UnixMicro())
randomInt := rand.Intn(10)
// return a number [0, 10)
Functions
Functions work in Go the very similarly to Java and JavaScript. Declare with the func
keyword, give the name, the parameters, the return and in the braces, give the functionality.
func equals (arg1 int, arg2 int) bool {
return arg1 == arg2
}
Where Go gets interesting is with the receivers, talked about under Objects, and with the ability to have multiple return values.
These are put in parentheses after the parameters. The return statement must return both types listed, and when the return is being handled, both values must be accounted for.
func RandomString(x int, n int) (string, error)
// Handle string and error return values
output, err := util.RandomString(3, 3)
It is very common for functions in Go to return multiple values, one usually being an error
, a type similar to Java's Exceptions.
Golang will not compile with unused variables, so what do developers do if a function has multiple return values, but they only care about one? In that case, developers use the _
character. It means "I know a value is here, but I don't care about it.
// Ignore second return value
output, _ := util.RandomString(3, 3)
Pointers
One thing to watch out for is pass-by-value. Golang is entirely pass-by-value. This means every value you pass as an argument in a function will be copied into a new variable in a new place in memory.
In other words, a variable passed as an argument will not be changed by the function, as the function is manipulating a different variable in a different place in memory.
Read this article on pass-by-value for a better description than I can give.
Developers can counteract this is by using pointers. Below, I demonstrate how to tell a function to expect a pointer and how to get a variable’s pointer.
The *
before a type tells Go to expect a pointer to a value of the given type.
// Make a function that expects a pointer to a string and returns a pointer to an intager.
func usePointer (s *string) *int
To get a pointer to a variable, use the &
character before the variable.
myString := "Hello World"
usePointer(&myString)
Reference Types
Now that I've told you that Go is entirely pass-by-value, let me tell you about the times it isn't.
Go really is entirely pass-by-value, but there are some datatypes known as reference types.
The article from Pointers talks about this.
These are types that don't directly store values (which is what value types do), but they instead store pointers. This means, even if the variable is copied, it still holds inside it a pointer to the actual value.
With reference types, developers do not need to get a pointer from them, as they contain a pointer. They can be used as normal, no pointer required!
Routing
Using the net/http package in the main()
function, developers can route URLs.
http.HandleFunc("/URL", (func(res http.ResponseWriter, req *http.Request) {
// handle responce and requests for /URL here
}))
HanldeFunc requires a URL pattern in a string and a handler function that has http.ResponseWriter
and *http.Request
parameters. The function can be stored in another file or package, but it must be properly formatted and imported.
Another option for routing is to store the routes in another file or package using http.ServeMux.
You must make sure that the Mux variable is accessible to the listener (see Listening) by either making the variable public, or by making a public function that returns a pointer to the Mux variable.
Mux := http.NewServeMux()
Mux.HandleFunc("/URL", (func(res http.ResponseWriter, req *http.Request) {
// handle responce and requests for /URL here
}))
Returning Go Templates
Developers can make Go templates using HTML pages. They can be simple static pages or complex dynamic pages. That topic is too big for this blog post, but I will demonstrate how to parse and return the file in a handle function (See Routing) using the html/template package.
t, _ := template.ParseFiles("templates/index.html")
t.Execute(res, nil)
Notice the use of the _
and the nil
, which is a pointer to nothing, similar (although not the same) to the null
.
The res
variable used is of type http.ResponseWriter
, the same one in the response handler.
Listening
The most important part in web app development is the listener. Without it, it does not matter how advanced the app is, it is useless. This is also found in the net/http package.
This is done with a very simple command in the main()
function.
(These examples will listen on port 3000)
If using http.HanldeFunc for Routing:
http.ListenAndServe(":3000", nil)
If using http.ServeMux for Routing:
mux := http.NewServeMux()
// list routing functions here
http.ListenAndServe(":3000", mux)
Conclusion
These have been some of the basics of Golang with a very basic overview of web app development. Thank you for taking the time to read this blog post, and I would like to again recommend the Golang documentation. It is a great tool. There are also countless articles and videos about web app development. The ones I've read and seen are very good. It takes time and dedication, but it is not overly complex (just another benefit of Golang).
Top comments (0)