OSGo.002: Variables, Constants, Zero Values, and Basic Types — var, :=, int, float64, bool, string, byte, and rune

Anime illustration of a diverse engineering team manipulating symbolic data types inside a futuristic systems lab

What Matters

  • Every Go variable always has a value: if you do not initialize it explicitly, Go gives it the zero value for its type.
  • var and := both create variables, but := is limited to function bodies while var works at package scope and can declare a variable without an explicit initializer.
  • Go’s basic types are intentionally explicit: integers, floating-point values, booleans, strings, bytes, and runes have different meanings, and Go generally does not perform silent numeric conversions for you.

Go tries to make basic program state predictable. Variables have known types, every declared variable starts with a defined value, and the language avoids many implicit conversions that can hide mistakes.

This lesson follows OSGo.001: What Is Go?, which introduced packages, the toolchain, go run, go build, and a first program. OSGo.002 moves inside the program itself: how to declare data, how Go chooses types, and what happens when you do not provide an initial value.

The official Go language specification defines variables as storage locations containing values of a particular type. That type determines which operations are valid and what zero value is used when initialization is omitted.

Telusko demonstrates Go variables and constants, providing a practical starting point for declaration syntax and fixed values.

Declaring Variables With var

The most explicit form places var, the variable name, and the type together:

var miners int

No initializer appears here, but miners is still usable. Because its type is int, Go initializes it to that type’s zero value, which is 0.

You can declare and initialize in one statement:

var miners int = 128
var model string = "S21"
var online bool = true

When the initializer makes the type obvious, Go can infer the variable type:

var miners = 128
var model = "S21"
var online = true

Short Variable Declarations With :=

Inside a function, Go provides the short declaration operator:

miners := 128
model := "S21"
efficiency := 17.5

:= both declares the variable and initializes it. The compiler infers the type from the expression on the right side.

The short form cannot be used at package scope. Package-level variables use var. Inside a function, := is common when the type is obvious from the initializer.

A Go community discussion on var versus := highlights an important beginner distinction: explicit zero-value declarations communicate different intent from short initialized declarations.

Every Variable Has a Zero Value

Go does not leave ordinary variables with an undefined garbage value. If you declare a variable without an initializer, the language initializes it to the zero value for its type.

  • numeric types → 0
  • bool → false
  • string → ""
  • pointers, slices, maps, channels, functions, and interfaces → nil
package main

import "fmt"

func main() {
    var count int
    var temperature float64
    var online bool
    var model string

    fmt.Println(count)       // 0
    fmt.Println(temperature) // 0
    fmt.Println(online)      // false
    fmt.Println(model)       // empty string
}

This design is one reason Go APIs often try to make a useful zero value possible. Later lessons on structs, slices, maps, mutexes, and interfaces will show where zero values are especially useful—and where nil needs more careful handling.

The official Go gopher mascot designed by Renee French
The Go gopher was designed by Renee French and is licensed under Creative Commons Attribution 4.0. Source: The Go Blog.

Go Has Several Integer Types

Go provides signed and unsigned integer types at defined widths:

  • int8, int16, int32, int64
  • uint8, uint16, uint32, uint64
  • int and uint, whose size is implementation dependent but is either 32 or 64 bits
  • uintptr, an unsigned integer type large enough to store the uninterpreted bits of a pointer value
var temperature int32 = -5
var fanRPM uint16 = 5400
var total uint64 = 10_000_000_000

Use plain int for ordinary integer arithmetic unless the problem, protocol, file format, API, or memory layout requires a particular width.

byte and rune Are Integer Aliases

Two Go names deserve special attention:

  • byte is an alias for uint8.
  • rune is an alias for int32 and is conventionally used for Unicode code points.
var packet byte = 0xff
var symbol rune = 'λ'
var gopher rune = '🐹'

The type aliases do not create brand-new underlying integer representations. Their names communicate intent: byte says “raw byte-sized data,” while rune says “Unicode code point.”

Yash Poonia’s Go course covers data types, variables, constants, strings, zero values, numeric types, runes, and the difference between var and :=.

Floating-Point and Complex Types

Go’s two floating-point types are float32 and float64. When an untyped floating literal needs a default type, Go normally chooses float64.

var efficiency float64 = 17.5
voltage := 12.25 // inferred floating type in this context

Go also includes complex64 and complex128 for complex-number arithmetic. These are less common in everyday backend programming but useful in scientific and signal-processing work.

Booleans Are Explicit

A bool can be true or false. Go does not generally treat integers or strings as automatically “truthy” or “falsy.” Conditions expect Boolean expressions.

online := true
hasAlarm := false

if online {
    println("running")
}

This keeps control flow explicit. Instead of asking whether an integer happens to be nonzero, write the comparison you mean.

Strings Are Immutable Byte Sequences

A Go string is an immutable sequence of bytes. Source-code string literals commonly contain UTF-8 text, but indexing a string returns a byte, not necessarily a complete Unicode character.

model := "S21"
message := "hello"

fmt.Println(message[0]) // byte value for 'h'

Later string lessons will cover UTF-8, byte slices, rune iteration, slicing, and why len reports bytes rather than a count of user-perceived characters.

Go Does Not Silently Mix Numeric Types

Even when two numeric types can represent similar values, Go generally requires an explicit conversion before combining them.

var racks int32 = 8
var spare int64 = 2

// total := racks + spare // compile error

total := int64(racks) + spare

This can feel strict at first, especially if you come from languages that perform extensive implicit promotion. The benefit is that the conversion is visible in the source code.

Constants Are Not Ordinary Variables

Constants are declared with const and represent values that can be determined at compile time.

const MaxRacks = 128
const DefaultVoltage = 12.0
const Banner = "Go Systems Lab"

Constants may be typed or untyped. Untyped constants are unusually flexible because Go can give them a concrete type when the surrounding context requires one, as long as the value is representable.

const Limit = 100

var a int = Limit
var b int64 = Limit
var c float64 = Limit

The constant Limit is not repeatedly converted from an existing runtime int variable. It is an untyped constant whose value can be represented in each target type.

Vikesh Yadav reviews the major Go declaration forms, constants, primitive data types, and type inference with practical examples.

Multiple Assignment and Declaration

Go can declare or assign several variables in one statement:

var model, site string
var rackCount, spareCount int

model, site = "S21", "Tacoma"
rackCount, spareCount = 8, 2

Short declarations can also create several variables at once:

model, watts := "S21", 3500

Inside the same scope, a short declaration can reuse existing variables only when at least one non-blank variable on the left side is new. This rule appears frequently when functions return multiple values.

Inspect Types While Learning

The fmt package can show both values and types while you experiment:

package main

import "fmt"

func main() {
    count := 128
    efficiency := 17.5
    online := true
    model := "S21"

    fmt.Printf("%v -> %T\n", count, count)
    fmt.Printf("%v -> %T\n", efficiency, efficiency)
    fmt.Printf("%v -> %T\n", online, online)
    fmt.Printf("%v -> %T\n", model, model)
}

%v prints the value in a default format, while %T prints the Go type. This is a useful learning and debugging technique when studying inference.

Common Beginner Mistakes

  • Using := at package scope: short declarations belong inside functions.
  • Assuming an uninitialized variable is undefined: Go gives it the type’s zero value.
  • Expecting automatic numeric promotion: explicit conversions are commonly required.
  • Confusing byte with a Unicode character: byte is uint8; rune is int32 used for Unicode code points.
  • Assuming string indexing returns a character: indexing returns one byte.
  • Treating constants exactly like variables: untyped constants have compile-time behavior that ordinary variables do not.
  • Adding explicit types everywhere: use inference when it keeps the code clear, and annotations where they communicate an important requirement.

Practical Exercise

  1. Create a new Go file named types.go.
  2. Declare four variables with var but no initializer: one int, one float64, one bool, and one string.
  3. Print their zero values.
  4. Create four more variables with := and inspect their inferred types using %T.
  5. Declare one byte and one rune, then print both their values and types.
  6. Create an int32 and an int64, attempt to add them directly, observe the compiler error, then fix it with an explicit conversion.
  7. Create an untyped constant and assign it to an int, int64, and float64.
  8. Run go fmt types.go, go vet types.go, and go run types.go.

Knowledge Check + Answers

  1. What happens if a Go variable has no explicit initializer? It receives the zero value for its type.
  2. Can := be used at package scope? No.
  3. What is the zero value of bool? false.
  4. What is the zero value of string? The empty string.
  5. What is byte an alias for? uint8.
  6. What is rune an alias for? int32.
  7. Does Go automatically add an int32 to an int64? No; an explicit conversion is required.
  8. What does %T print with fmt.Printf? The value’s Go type.
  9. What is the difference between a typed and untyped constant? A typed constant already has a specific type; an untyped constant can receive a concrete type from context when representable.
  10. When is var especially useful? At package scope, when an explicit type matters, or when you intentionally want the zero value without an initializer.

Primary References

Elementary Review

Go variables are never “empty” in the undefined sense. Declare them with var or, inside functions, with :=. If you omit the initializer, Go supplies the type’s zero value. Use integer and floating types deliberately, remember that byte and rune are integer aliases with useful semantic meaning, and treat constants as compile-time values rather than ordinary mutable storage.

Editor’s Note

This lesson uses a unique generated 1200×630 anime featured image and a separate official Go gopher body image. Three distinct programming videos are distributed across the lesson rather than stacked together. Standard responsive Gutenberg headings, paragraphs, lists, code, image, and embed blocks are used throughout; ordinary lesson prose is not placed inside bordered, shaded, card-style, callout, panel, or fixed-width text boxes.

BitcoinVersus.Tech content is provided for informational and educational purposes.

Leave a Reply