Channels ▼


Getting Going with Go

The program begins by checking to see whether it was invoked with any command-line arguments. If it wasn't, len(os.Args) will be 1 (recall that os.Args[0] holds the program's name, so the slice's length is normally at least 1), and the first if statement is satisfied. In this case we output a suitable usage message using the fmt.Printf() function that accepts % placeholders similar to those supported by C/C++ printf() or Python's % operator.

The path/filepath package provides path manipulation functions—for example, the filepath.Base() function returns the basename (that is, the filename) of the given PATH. After outputting the message the program terminates using the os.Exit() function and returns 1 to the operating system. On Unix-like systems a return value of 0 is used to indicate success, with nonzero values indicating a usage error or a failure.

The use of the filepath.Base() function illustrates a nice feature of Go: When a package is imported, no matter whether it is top-level or logically inside another package (e.g., path/filepath), we always refer to it using only the last component of its name (that is, filepath). It is also possible to give packages local names to avoid name collisions.

If at least one command-line argument was given, the first one is copied into the stringOfDigits variable (of type string). To convert the number that the user entered into big digits we must iterate over each row in the bigDigits slice to produce each line of output, that is, the first (top) string for each digit, then the second, and so on. We assume that all the bigDigits' slices have the same number of rows and so take the row count from the first one. Go's for loop has various syntaxes for different purposes; in this example, for ... range loops return the index positions of each item in the slices they are given.

The row and column loops part of the code could have been written like this:

for row := 0; row < len(bigDigits[0]); row++ { 
    line := ""
    for column := 0; column < len(stringOfDigits); column++ { 

This is a form familiar to C, C++, and Java programmers and is perfectly valid in Go. (Unlike C, C++, and Java, in Go the ++ and -- operators may be used only as statements, not expressions. Furthermore, they may only be used as postfix operators, not prefix operators. This means that certain order of evaluation problems cannot occur in Go—so thankfully, expressions like f(i++) and a[i] = b[++i] cannot be written in Go.) However, the for ... range syntax is shorter and more convenient.

At each row iteration, the code sets that row's line to be an empty string. Then, we iterate over the columns (i.e., the characters) in the stringOfDigits string we received from the user. Go strings hold UTF-8 bytes, so potentially a character might be represented by two or more bytes. This isn't an issue here because we are only concerned with the digits 0, 1, ..., 9 each of which is represented by a single byte in UTF-8 and with the same byte value as in 7-bit ASCII.

When we index a particular position in a string we get the byte value at that position. (In Go the byte type is a synonym for the uint8 type.) So we retrieve the byte value of the command-line string at the given column and subtract the byte value of digit 0 from it to get the number it represents. In UTF-8 (and 7-bit ASCII) the character '0' is code point (character) 48 decimal, the character '1' is code point 49, and so on. So if, for example, we have the character '3' (code point 51), we can get its integer value by doing the subtraction '3' -'0' (i.e., 51 – 48) which results in an integer (of type byte) of value 3.

Go uses single quotes for character literals, and a character literal is an integer that's compatible with any of Go's integer types. Go's strong typing means we cannot add, say, an int32 to an int16 without explicit conversion, but Go's numeric constants and literals adapt to their context, so in this context '0' is considered to be a byte.

If the digit (of type byte) is in range, we can add the appropriate string to the line. (In the if statement the constants 0 and 9 are considered to be bytes because that's digit's type, but if digit were of a different type, say, int, they would be treated as that type instead.) Although Go strings are immutable, the += append operator is supported to provide an easy-to-use syntax. (It works by replacing the original string under the hood.) There is also support for the + concatenate operator which returns a new string that is the concatenation of its left and right string operands.

To retrieve the appropriate string, we access the bigDigits's slice that corresponds to the digit, and then within that to the row (string) we need.

If the digit is out of range (due to the stringOfDigits containing a nondigit, for example), we call the log.Fatal() function with an error message. This function logs the date, time, and error message—to os.Stderr if no other log destination is explicitly specified—and calls os.Exit(1) to terminate the program. There is also a log.Fatalf() function that does the same thing and which accepts % placeholders. We didn't use log.Fatal() in the first if statement because we want to print the program's usage message without the date and time that the log.Fatal() function normally outputs.

Once all the number's strings for the given row have been accumulated the complete line is printed. In this example, seven lines are printed, because each digit in the bigDigits slice of strings is represented by seven strings.

One final point is that the order of declarations and definitions doesn't generally matter. So in the bigdigits/bigdigits.go file we could declare the bigDigits variable before or after the main() function. In this case we have put main() first since for this article's examples we usually prefer to order things top-down.

These two examples have covered a fair amount of ground, but both of them show material that is familiar from other mainstream languages even though the syntax is slightly different. Next week's article will examine additional features of Go, including some advanced aspects.

This article is adapted from the author's recent book, Programming in Go.

Mark Summerfield is an independent trainer, consultant, and writer specializing in Go, Python, C++, and Qt.

Related Reading

Go Tutorial: Object Orientation and Go's Special Data Types

RESTful Web Service in Go Powered by the Google App Engine

A Brief Tour of the Go Standard Library

Why Not Go?

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.