Go Basics: Variables, Constants, Primitive Types and Type Conversion
Module 1: Go Language Intro & Dev Environment | Lesson: m01-l04 | Level: Beginner After this lesson you will be able to: declare variables and constants the Go way, understand the zero-value mechanism and the type system, and correctly use the standard library for type conversion.
Learning Objectives
- Use
varand:=to declare variables correctly, and understand the difference between multi-variable assignment and parallel assignment. - Explain the zero-value mechanism and list the zero values of
int,string,bool,float64and the reference types. - Use
constandiotato define enumeration constants, and understand the implicit conversion rules of untyped constants. - Use the
strconvpackage to convert explicitly between strings and numbers.
Core Concepts
2.1 Variable Declaration: var and :=
In Go, a variable is a container that stores data. Go offers two main ways to declare variables: the var keyword and the short variable declaration :=.
1. What
- var declaration: explicitly declares the variable's type. The syntax is var name type = value. If you omit value, the variable is given the zero value of its type.
- := short declaration: infers the type implicitly. The syntax is name := value. It can only be used inside a function, and the left-hand side must contain at least one new variable.
2. Why it is designed this way
Go emphasizes explicitness and simplicity. var suits package-level variables or cases where you want an explicit type; := suits local variables, cutting down boilerplate and improving readability.
3. How
// Explicit declaration
var age int = 18
var name string = "Alice"
// Implicit declaration (short variable)
count := 10
isActive := true
// Multi-variable declaration
var x, y int = 1, 2
a, b := 3, 4
2.2 The Zero-Value Mechanism
In Go, a variable that is declared without explicit initialization automatically receives the type's zero value. This avoids undefined behavior and is a manifestation of Go's safety.
| Type | Zero value |
|---|---|
int, int8, int16, int32, int64 |
0 |
float32, float64 |
0.0 |
bool |
false |
string |
"" (empty string) |
| pointers, slices, maps, channels, functions, interfaces | nil |
2.3 Constants and iota
Constants are fixed at compile time and cannot be modified at runtime.
1. iota enumeration
iota is a predeclared identifier that starts at 0 in a const block and increments by 1 on each line.
- Note: iota only works inside const blocks; it cannot be used in a var block.
- Rule: inside each const block, iota starts at 0 and increments by 1 per constant specification; a new const block starts again at 0, and you can skip a line with _.
2. Untyped constants
Go supports untyped constants, such as 3.14 or 100. They have no concrete type until they are assigned to a variable or used in a context that demands a type, at which point their type is determined by context. This lets constants convert implicitly to compatible types.
2.4 Primitive Types and Type Conversion
Go is a strongly typed language and forbids implicit type conversion. Conversions between different primitive types must be explicit.
1. Primitive types
- Integers: int, int8, int16, int32, int64, uint, uint8 (alias byte), uint16, uint32, uint64
- Floating point: float32, float64
- Complex: complex64, complex128
- Characters: byte (alias of uint8), rune (alias of int32)
- Boolean: bool
- String: string
2. Explicit type conversion
The syntax is T(v), where T is the target type and v is an expression.
- Numeric conversion: int(f) truncates a floating-point number to an integer.
- String conversion: use the strconv package. For example, strconv.Atoi(string) converts a string to int, and strconv.Itoa(int) converts an integer to a string.
Important rule: constant truncation
When an untyped constant is converted to a typed variable, the compiler reports an error if precision would be lost (such as float to integer). For example, int(3.14) is illegal: 3.14 is an untyped floating-point constant, and converting it directly to int loses precision. You must first assign it to a typed variable and then convert: var f float64 = 3.14; var i int = int(f).
Example Code
Example 1: Variable Declaration, Zero Values and iota Enumeration
This example shows the difference between var and :=, demonstrates the zero-value mechanism, and uses iota to define color constants.
package main
import "fmt"
// A package-level variable declared with var; its zero value is 0.
var globalCounter int
func main() {
// 1. Variable declaration
var name string // zero value is ""
var age int = 18
localVar := "Hello" // short declaration, type inferred as string
fmt.Printf("Name: %q, Age: %d, LocalVar: %s\n", name, age, localVar)
fmt.Printf("Global Counter (zero value): %d\n", globalCounter)
// 2. iota enumeration
type Color uint8
const (
Red Color = iota // 0
Green // 1
Blue // 2
)
fmt.Printf("Red: %d, Green: %d, Blue: %d\n", Red, Green, Blue)
}
Expected output:
Name: "", Age: 18, LocalVar: Hello
Global Counter (zero value): 0
Red: 0, Green: 1, Blue: 2
Example 2: Type Conversion and Using strconv
This example demonstrates explicit numeric conversion, the limits on constant conversion, and converting between strings and integers with strconv.
package main
import (
"fmt"
"strconv"
)
func main() {
// 1. Explicit numeric conversion
var f float64 = 3.14
// Note: you cannot write var i int = int(3.14) directly,
// because the untyped constant 3.14 cannot be converted to int directly.
// It must first be assigned to a typed variable and then converted.
var i int = int(f)
fmt.Printf("Float: %f -> Int: %d\n", f, i)
// 2. Converting between string and integer
strNum := "123"
num, err := strconv.Atoi(strNum)
if err != nil {
fmt.Printf("Error converting %s to int: %v\n", strNum, err)
return
}
num++
backToStr := strconv.Itoa(num)
fmt.Printf("String: %s -> Int: %d -> String: %s\n", strNum, num, backToStr)
// 3. A bad conversion example (commented out, otherwise compilation fails)
// var badInt int = int(3.14) // compile error: cannot convert 3.14 (untyped float constant) to type int
}
Expected output:
Float: 3.140000 -> Int: 3
String: 123 -> Int: 124 -> String: 124
Common Mistakes & Pitfalls
-
Wrong assumption: believing
var i int = 3.14is legal because Go allows implicit conversion.- Why: Go forbids implicit conversion between typed values.
3.14is an untyped floating-point constant, but when it is assigned to anintvariable, the compiler checks for precision loss and reportscannot use 3.14 (untyped float constant) as int value in variable declaration (truncated). Only untyped constants convert implicitly between compatible types (e.g.var f float64 = 1). - Correct approach: convert explicitly:
var f float64 = 3.14; var i int = int(f).
- Why: Go forbids implicit conversion between typed values.
-
Wrong assumption: using
iotainside avarblock.- Why:
iotais an enumeration counter specific toconstblocks. It is not supported invarblocks; writingvar ( A = iota )causes the syntax errorsyntax error: unexpected newline, expected type. - Correct approach: use
iotaonly inconstblocks. Group package-level variables withvar (...), but do not useiotainside.
- Why:
-
Wrong assumption: using
int(3.14)directly as a constant conversion.- Why: the untyped constant
3.14cannot be converted directly tointbecause it loses the fractional part. The compiler reportscannot convert 3.14 (untyped float constant) to type int. - Correct approach: first assign it to a typed variable and then convert:
var f float64 = 3.14; var i int = int(f).
- Why: the untyped constant
Best Practices
- Prefer
:=for local variables: inside a function,:=makes the code more concise, and type inference is usually accurate. Usevaronly when you need an explicit type or are declaring package-level variables. - Leverage zero values to simplify initialization: do not explicitly initialize variables to
0or""unless it carries specific meaning. Go's zero values are usually safe defaults. - Use
iotafor enumeration constants: when you need a group of related constants (such as status codes, colors, error codes), use aconstblock withiotato avoid magic numbers. - Convert types explicitly: always use
T(v)for type conversion; do not rely on implicit conversion (which barely exists in Go). For numeric conversions, watch out for truncation. - Use
strconvfor string conversion: do not hand-parse strings; use the standardstrconvpackage, which is optimized and handles edge cases.
Exercises
- Concept question: explain the zero-value mechanism, give the zero values of
int,string,boolandfloat64, and list which types (pointer/slice/map/channel/function/interface) havenilas their zero value. - Coding exercise: write a function
convertAndPrintthat takes afloat64argument, converts it toint, then usesstrconv.Itoato turn the result into a string, and finally prints that string. -
Advanced/debugging exercise: the code below tries to convert a floating-point constant directly to an integer. Find the error and fix it. ```go package main
import "fmt"
func main() { var discount int = int(3.14) fmt.Printf("Discount: %d\n", discount) } ```
Reference Answers
Reference Answers (click to expand / collapse)
Question 1
Answer:
The zero value is the default value a Go variable takes when it is not explicitly initialized.
- The zero value of int is 0.
- The zero value of string is "" (the empty string).
- The zero value of bool is false.
- The zero value of float64 is 0.0.
- The zero value of pointers, slices, maps, channels, functions and interfaces is nil.
Question 2
package main
import (
"fmt"
"strconv"
)
func convertAndPrint(f float64) {
// Explicitly convert to int, truncating the fractional part
i := int(f)
// Convert the int to a string
s := strconv.Itoa(i)
fmt.Println(s)
}
func main() {
convertAndPrint(3.14) // prints: 3
}
Explanation: the function takes a float64, converts and truncates it explicitly with int(f), then turns it into a string with strconv.Itoa and prints it.
Question 3
The problem:
The line var discount int = int(3.14) is a compile error. The reason is that the untyped constant 3.14 cannot be converted directly to type int because it loses precision (truncation). The Go compiler does not allow this kind of implicit precision-losing conversion.
Fixed code:
package main
import "fmt"
func main() {
// The correct approach: assign to a typed variable first, then convert
var f float64 = 3.14
var discount int = int(f)
fmt.Printf("Discount: %d\n", discount)
}
Lesson Summary
- Go offers two ways to declare variables,
varand:=;:=is more concise but works only inside functions. - Every variable has a well-defined zero value, and the zero value of reference types (pointers, slices, etc.) is
nil. iotais an enumeration counter inconstblocks, starting at 0 and incrementing; it applies only to constants.- Go forbids implicit type conversion; you must use
T(v)explicitly, and constant conversion must not lose precision. - The
strconvpackage is the standard tool for converting between strings and numbers.
Next lesson preview: operators, control flow and variable scope — Go's idiomatic if, for and switch.