In Go, although errors are a controversial subject, they are in fact very simple. As programmers of Go we also spend a lot of our time writing if err != nil. But we often also need to create these errors and pass them back to other functions to handle. The errors package allows to create errors, as per the error interface, which can be dealt with like any other error. In our example below we handle the error on main() and produce the error in DoSomething().
In Go, we use structs to define and group data, as we would use classes in other OOP languages. However, in Go the naming of attributes within the struct is important because if it starts with a lower-case it’s seen as private and with an upper-case first letter it’s seen as public. We can encode these structs into data formats like json but we might want to rename the fields, struct tags allow us to do this.
We’ve already got a post on converting an integer to a string but the process of converting a variable of type uint64 to a string is a little different. For an int we can use Itoa(), but for an unsigned int 64 we can still use strconv but we can use the FormatUint function instead.
The program below is designed to print out the current state of how much memory is being used, how much has been used and how much the system has reserved. You only really need the PrintMemUsage() function to do this, the rest of the main() is there to illustrate it working (with a gif showing this at the end of this post). The most important figure if often the Alloc which is the amount allocated heap objects.
In Go, the traditional while true loop, found in many programming languages, can done through the for keyword. Below are two alternative versions, a for can work as an infinite loop without any parameters, or with a true boolean.
We often need to measure execution time in programming, as it helps us understand the programs we’re working with and knowing where potential bottlenecks are occurring. In Go, we are able to use the time package and the defer keyword to run our time tracking function at the end of our long function. The parameters will be calculated at the beginning of the function (thus freezing the start time). Once the deferred function is running, all we need to do is show the difference in start time and current time.
We can use the net/http package to find the content type, or mime type, of a file. To do this, we open the file and read the first 512 bytes (as the DetectContentType() function only uses the first 512 bytes, there’s no point in doing more than needed). This function will then return a mime type, like application/json or image/jpg for instance.
When running a Go program in the terminal, your program could receive a signal interrupt from the OS for any number of reasons. One of which is if the user presses Ctrl+C on their keyboard (or whatever your operating system/terminal is set to). We can execute some code when this interrupt is received, mainly to clean up and reset what we were working on. In our example we use a goroutine to listen for the interrupt from signal.
We’ve already covered basic downloading of files - this post goes beyond that to create a more complete downloader by including progress reporting of the download. This means if you’re pulling down large files you are able to see how the download’s going. In our basic example we pass the response body into io.Copy() but if we use a TeeReader we can pass our counter to keep track of the progress.
This example shows how to download a file from the web on to your local machine. By using io.Copy() and passing the response body directly in we stream the data to the file and avoid having to load it all into the memory - it’s not a problem with small files, but it makes a difference when downloading large files. We also have an example of downloading large files with progress reports.