|
By Nathan Youngman In this article, excerpted from Learn Go, I will introduce you to the concept of types in Go. |
Every variable has a type. The type determines the values a variable can hold. Take an example from the real world. There are millions of phone numbers in the U.S., each number is a value, whereas a type would define the 10 digit representation.
Go doesn’t provide a phone number type out-of-the-box, but you can build one from primitive types. These include a string type for multilingual text, a Boolean type for true and false, and numerous numeric types for any occasion.
The word Go and the number 28487 are both represented with the same zeroes and ones on an x86 computer (0110111101000111). The type establishes what those bits and bytes mean. One is a string of two characters, the other is a 16-bit integer (2 bytes).
A variable’s type also establishes what behavior is appropriate for it. Numbers can be divided, text can be converted to uppercase, and phone numbers can be dialed. Likewise, nonsensical behavior is prevented. By using types, the Go compiler will report an error if you attempt to uppercase a number or perform division on text.
The unseen types
Every variable has a type. When you don’t specify a type, Go will determine a variable’s type for you. The following three lines of code are equivalent, because the Go compiler will infer that countdown is a string, based on the quoted text to its right.
countdown := "Launch in T minus 10 seconds." ❶ var countdown = "Launch in T minus 10 seconds." var countdown string = "Launch in T minus 10 seconds."
❶ short declaration syntax
While it is valuable to know that countdown has a string type, it is superfluous to specify string. You, me, and the Go compiler can all infer that countdown is a string of text just by looking.
The golint tool, which will be discussed further in Appendix B, provides hints for coding style. It discourages the clutter with the following message:
“should omit type string from declaration of var countdown; it will be inferred from the right-hand side”
— golint
It isn’t an error to specify string, so you can if you believe it adds clarity. But as a matter of style, try to remember which types Go will infer, and rely on type inference. It will make your code less noisy.
Types can be inspected
If you are curious which type the Go compiler inferred, the Printf function provides the %T format verb to display a variable’s type.
Listing 1 Inspect a variable’s type: inspect.go
countdown := "Launch in T minus 10 seconds."fmt.Printf("%T", countdown) ❶
❶ Print string
Experiment
Navigate to the Go Playground at play.golang.org and type Listing 1 into the body of the main function.
- Declare
countdownwith different values and run the program to see which types Go infers. Use a whole number, a real number, and the wordtrue(without quotes). - Write down the types Go infers for the values you used. These are the most common types.
Types have default values
In Listing 1, the countdown variable is declared and initialized with a value in one step. It is also possible to declare a variable with no value and assign a value to it later:
var countdown stringcountdown = "Launch in T minus 10seconds." fmt.Println(countdown)
This is handy when you want to assign a value conditionally and still have the variable available outside the scope of the condition:
Listing 2 Assigning a value later: default.go
launch := falsevar countdown stringif launch {countdown = "Launch in T minus 10 seconds."}fmt.Println(countdown)
If the rocket is not ready to launch, countdown will not be assigned a new value, so the default value of countdown is displayed.
In Go, each type has a default value, called the zero value. The zero value for Booleans is false. For a string, the zero value is an empty string. Unsurprisingly, the zero value for numeric types is zero.
Listing 2 declares countdown with no value, which has identical behavior to:
countdown := ""
The difference is a matter of style.
In Listing 2, the launch variable is initialized explicitly to false, even though false is the default value for Booleans. This suggests that there is an important reason for launch to be false.
On the other hand, not specifying a value for countdown hints that the real value is yet to come.
Types are static
In Go, once a variable is declared, it has a type and that type cannot be changed. Attempting to use a variable with a value of a different type will cause the Go compiler to report an error:
var greeting = "Hello Universe" greeting= 42 ❶var num = 42 num= 3.14 ❷
❶ This reports an error: greeting can only store text
❷ This reports an error: num can only store whole numbers
The term for this behavior is static typing. Another class of languages use dynamic typing, where each value has an associated type, and variables can hold values of any type. In those languages (JavaScript, Python, Ruby, etc.) code similar to the above would execute.
|
Note |
Go does support dynamic typing for situations where a type is unknown. For example, you can pass either text or numbers to the |
Types don’t mix
A variable’s type establishes the behavior that is appropriate for it. Numbers can be added, strings can be joined. To join two strings together, use the plus operator:
countdown := "Launch in T minus " + "10 seconds."
If you try to join a number to a string, the Go compiler will report an error:
countdown := "Launch in T minus " + 10 + " seconds." ❶
❶ invalid operation: mismatched types string and int
|
Sidebar |
Mixing types in other languages When presented with two or more different types, some programming languages make a best effort to guess the programmer’s intentions. Both JavaScript and PHP can subtract 1 from the string
❶ 9 in JavaScript and PHP To accomplish this in Go, you will need to first convert That said, if In languages that coerce types, the code’s behavior is less predictable to anyone who hasn’t memorized a myriad of implicit behaviors. The plus operator in both Java and JavaScript coerces numbers to strings to be joined, whereas PHP coerces the values to numbers and does the math. Once again, Go reports a mismatched types error.
❶ “102” in JavaScript or Java, 12 in PHP |
Another example of mismatched types occurs when attempting a calculation with a mix of integer and floating point types. Real numbers like 365.2425 are represented with a floating point type, while Go infers that whole numbers are integers.
age := 38 ❶marsDays := 687 ❶earthDays := 365.2425 ❷fmt.Println("I am", age*earthDays/marsDays, "years old on Mars.") ❷
❶ age and marsDays are integers
❷ earthDays is a floating point type
❸ invalid operation: mismatched types
If all three variables were integers, the calculation would succeed, but then earthDays would need to be 365 instead of the more accurate 365.2425.
Alternatively, the calculation would succeed if age and marsDays were floating point types (38.0 and 687.0 respectively). Go doesn’t make assumptions about which you would prefer.
