Skip to main content

Command Palette

Search for a command to run...

Basics of Variables, Constants, and Data Types in Go

Exploring Variables, Contents, and Data Types in Go Programming

Updated
6 min read
Basics of Variables, Constants, and Data Types in Go

In the previous article, we installed Go on our system and ran our first "Hello, World!" program. Now, in this article, we will learn about variables and data types. This is an important topic because we need to store data in memory while running the code to reuse it throughout the program. To do that in Go, there are some rules. So let's dive deep into this.

What are Variables in Go?

A variable is a named memory location that stores a value.

In Go, we declare variables using the following syntax or keywords:

  • var keyword

  • := → using this syntax for short and fast declaration.

Declaring Variables Using var

package main
import "fmt"

func main() {
    var name string = "Rohit Lokhande"
    var age int = 25
    fmt.Println(name, age)
}

Declaring Variable Using Short Declaration Syntax

name := "Rohit"
age := 25

:= this will automatically infers the type based on the value.

Note := this declaration can only be used inside functions.

Grouped Variable Declaration

var(
   name="Rohit"
   age = 25
   city = "Pune"
)

Global vs Local Variable

Variables declared outside any function are package-level, which are accessible within the package.

package main
import "fmt"
var global = "I am global"
func main() {
   local := "I am local"
   fmt.Println(global)
   fmt.Println(local)
}

iota keyword

Go uses iota to create enumerated constants easily. It is a keyword in Golang that holds an integer value.

It is typically used within constant declarations to generate a series of related values, incrementing by 1 for each subsequent constant.

const (
   Sunday = iota
   Monday
   Tuesday
   Wednesday
)
fmt.Println(Sunday, Monday, Tuesday) // 0 1 2

Every new line with a constant increments iota by 1. This is used widely for status codes, enums etc

Using iota with Expressions

This is also used with expressions to define more complex constant values. Let’s understand with an example. If we want to define constants representing file sizes in bytes, kilobytes, megabytes, and so on, we can achieve this in a simple way using iota.

pacakge main
import "fmt"
const (
  _ = iota // Discard the first value (0)
  KB = 1 << (10 * iota) // 1 << (10 * 1)
  MB = 1 << (10 * iota) // 1 << (10 * 2)
  GB = 1 << (10 * iota) // 1 << (10 * 4)
)
func main() {
    fmt.Println("KB:", KB)
    fmt.Println("MB:", MB)
    fmt.Println("GB:", GB)
    fmt.Println("TB:", TB)
}

In this, we use bitwise left shifts (<<) in conjunction with iota to calculate the constant values for different file sizes.

Rules to Remember While Declaring Variable

  • All variables must be used otherwise Go will throws a compile-time error.

  • Variables are block-scoped.

  • You can declare multiple variable together

  •   var x, y = 10,20
    

Why does Go require you to use every declared variable?

  • Catches mistakes early

    If you declare a variable but forget to use it, the compiler will let you know right away, preventing a runtime bug from hiding that mistake.

  • Encourages clean code

    No unused variables mean the code is easier to read and has fewer maintenance issues.

  • Smaller/safer binaries

    Unused imports and values can make builds more complicated or cause unexpected problems. Not allowing them helps keep builds straightforward and predictable.

Example for above rule

Broken- compiler error code

package main
func main() {
   var x int // declared but never using
   y := 10   // declared but never used
}

Compiler will complain: x declared and not used

Fixed - use the variables

package main

import "fmt"

func main() {
    var x int
    y := 10
    x = y * 2
    fmt.Println(x) // now both x and y are used
}

How to intentionally ignore a value

If you we really want to discard a value, we can use the black identifier _ . This tells the compiler “I intentionally don’t need this.“

  • Ignore a return value:

      x, _ := someFunc() // ignore second return value
    
  • Mark a value as used (silence unused variable):

      var x = someFunc()
      _ = x // explicitly mark "x" as used so compiler won't complain
    

Best Practices for Unused Compile Time Error

    • If the compiler says "declared and not used," either remove the declaration or actually use the variable.

      • While experimenting, _ = x is a quick way to silence errors, but prefer to remove dead code before committing.

      • For multi-value returns where only some values matter, use _ for the ones you want to drop.

Constants in Go

Constant is an immutable value - once defined, it cannot be changed.

Declaring Constants

const PI 3.14
const Greeting = "Hello, Go!"

Constants can also be grouped

const (
    StatusOK = 200
    StatusNotFound = 404
)

If you try to modify a constant, Go will throw an error:

PI =3.142145 // ❌ compile-time error

Data Types in GO

CategoryTypesExample
Numericint, float32,float64,complex64,complex128var age int = 5
Stringstringvar name string = “Rohit”
Booleanboolvar isDev bool = true
Derivedarray,slice,map,struct,interfaceCovered later.

In this section, we won't dive deep into the differences between float32, float64, and other numeric types. We will discuss non-primitive data types like arrays and slices later.

Type inference

Go automatically infers type if not specified

count:= 10 // int
price:=99.99 // float64
message:="Hello" // string

What is Type Inference?

Type inference means Go can automatically determine the data type of a variable based on the value you assign to it, so you don’t have to explicitly write the type every time.

Even though Go is statically typed, meaning types are checked at compile time, not runtime, it doesn’t always require you to write them explicitly because the compiler can infer them.

Rules for Inference

  1. Inference happens only during declaration, not late:

     var x int
     x = 10.5 // Error - 10.5 is float64, not int
    
  2. You can’t mix inferred and explicit types in one declaration

     var a, b = 1, "hello"   // ✅ both inferred
     var c, d int = 1, "hi"  // ❌ type mismatch for d
    
  3. Inference doesn’t mean dynamic typing

    Once inferred, the type is fixed and checked at compile time.

Zero Values for Uninitialized variables

In Go, uninitialized variables are not garbage they take zero values automatically

TypeZero Value
int, float0
string““
boolfalse
pointer,slice,mapnill

Type Conversion

Go doesn’t support implicit conversions you must convert explicitly

var a int = 10
var b float64 = float64(a)
fmt.Println(b)

Conclusion

Variables, constants, and data types form the foundation of any Go program. Go’s simple but strong type system encourages clean, predictable code, so you always know what’s stored where.

In the next post, we’ll dive into Functions in Go, where you’ll learn how to organize and reuse logic efficiently.