JavaRush /Courses /Go SELF /Declaring variables: var, :=

Declaring variables: var, :=

Go SELF
Level 6, Lesson 1
Available

1. What is a variable in Go: name, type, and value

When you’re just starting to program, it’s easy to think of a variable as a “little box for a number”. That’s not a bad start, but in Go this “box” has a passport: a name, a type, and the current value. And the most important thing: the type is fixed at declaration and doesn’t “change shoes” on the fly. This disciplines the code and makes it more predictable (and yes, sometimes it’s annoying—but more often it saves you from weird bugs).

Imagine a variable as a conference badge: the badge shows the name (how to address it), the “role” (type), and the current “state” (value). If the badge says int, you can’t suddenly write a string "hello" on it—compiler security won’t let it through.

Declaration vs assignment: why these are different operations

In practice, beginners most often get confused not by syntax, but by meaning: what’s the difference between “create a variable” and “change the value in an already created variable”. In Go, these actions are separated very clearly. It’s like the difference between “create a new character in a game” and “change their outfit”: the character’s name appears when you create them, and after that you just update their parameters.

In Go, there are three forms we’ll use every day:

  1. var — variable declaration (create a name in the current scope).
  2. := — short variable declaration (also creates a name, usually inside functions).
  3. = — assignment (the name must already exist; we change the value).

Let’s put it into a table—this makes it easier for your brain to “grab onto”:

Syntax What it does When to use it
var x int
declares x of type int, gives a default value when you want to explicitly specify the type or declare ahead of time
var x = 10
declares x; the type is inferred from 10 when you have a starting value and the type is obvious
x := 10
declares x (type inferred), short form usually inside main and other functions
x = 10
assigns 10 to an already existing x when x is already declared

And here’s the key phrase of the day: var and := create a variable, while = only changes its value.

2. Declaring with var: two variants

var looks a bit more “official” than :=. Sometimes that’s even nice: the code feels more serious, as if you put a jacket on the variable. But the main thing is that var shows the type well and is useful when you want to declare a variable ahead of time and fill it later (for example, after fmt.Scan or after checking a condition).

var name Type: declared, default value

When you write var count int, you create a variable count of type int. If you don’t give it an initial value, Go still won’t leave it “with garbage”—it will set the default value (for int that’s 0). We’ll break down default values in detail separately, but it’s already important to know: the program won’t read “random stuff from memory”.

A minimal example to feel the difference between declaration and assignment:

package main

import "fmt"

func main() {
	var count int // declared
	count = 3     // assigned
	fmt.Println(count) // 3
}

Here var count int creates a variable, and the line count = 3 only changes its value.

var name = expr: declared and initialized immediately

If you write var x = 10, Go looks at the right-hand side and infers the type automatically. This is called type inference. For example, if there’s a string on the right, the type will be string. In official Go materials, this is often explained with a very clear example: var str = "Hello, 世界" means the same as var str string = "Hello, 世界".

Here’s a small example:

package main

import "fmt"

func main() {
	var name = "Gopher"
	var age = 10
	fmt.Println(name, age) // Gopher 10
}

Here name becomes a string, and age becomes an int, because Go inferred the type from the right-hand side.

4. := and = in everyday code

Short declaration := inside a function

:= is a “quick declaration”. It’s used almost all the time inside main, because that’s where we write the main flow of the program, and we want fewer ceremonies. In practice, := makes code compact and readable: you immediately see the name and the initial value. It’s like saying, “here’s a variable, and here’s its start”.

Example:

package main

import "fmt"

func main() {
	x := 10        // declared + initialized
	x = x + 5      // updated an existing one
	fmt.Println(x) // 15
}

Pay attention to the rhythm: the first line creates the variable, then we use = to update it. This is a very typical Go coding style.

There’s an important rule to memorize for now like a mantra: if the variable already exists and you want to change it—use =. If you write :=, you are most likely creating a new variable (and that is sometimes not what you intended).

Assignment =: changing the value of an existing variable

The = operator does not create a variable. It requires that the name has already been declared in the current scope (or in an outer scope that is visible). So x = 10 without a prior declaration of x will lead to a compilation error—and that’s normal: the compiler honestly says, “I don’t know what x is.”

An example of the “correct” sequence:

package main

import "fmt"

func main() {
	var total int
	total = 100
	total = total - 30
	fmt.Println(total) // 70
}

Here total is created via var, and then updated twice using =.

By the way, due to Go’s strict typing, it doesn’t like to automatically “mix” different numeric types: if variables are of different types, the compiler will ask you to be more explicit. This is part of Go’s philosophy: it’s better to forbid ambiguity upfront than to catch weird effects later.

5. Block scope {}: where a variable is “visible”

Now the most interesting part (and the most common “why doesn’t it work?!” among beginners). In Go, curly braces {} define scope: the part of code where variable names exist and are accessible. You can think of a block as a room: you can bring things (variables) into it, use them inside, but when you leave the room—things created inside stay there.

Schematically it looks like this:

main {
    x  // lives throughout main
    if {
        y // lives only inside if
    }
    // here y no longer exists
}

This isn’t “Go being picky”, it’s protection against chaos: if a variable is needed only inside a small block, it’s better not to let it live longer—there’s less chance you’ll accidentally use it where you shouldn’t.

Nested if blocks

The simplest example: a variable declared inside if is not accessible outside.

package main

import "fmt"

func main() {
	x := 10

	if x > 0 {
		y := x * 2
		fmt.Println("inside:", y) // inside: 20
	}

	fmt.Println("outside:", x) // outside: 10
}

Here y exists only inside the if block. That’s convenient: y is a “temporary calculation”, it’s not needed later.

If you try to write fmt.Println(y) after the if, the compiler will say that y is undefined. And that’s a good moment: the compiler literally saves you from using a variable that has already “died”.

Loop variables in for

With the for loop, it’s a similar story: everything declared in the loop header usually lives inside the loop.

package main

import "fmt"

func main() {
	for i := 1; i <= 3; i++ {
		fmt.Println(i) // 1, then 2, then 3
	}
}

The variable i is created within the loop. After the loop finishes, it’s no longer needed, and Go doesn’t let it “hang around” in main. This makes code cleaner: fewer “extra” names that you might accidentally use later.

When to declare a variable outside vs inside

There’s a very practical logic here. If you need the value after the block, declare the variable outside and do an assignment inside the block. If you need the value only for an internal computation, declare it right inside the block so it doesn’t interfere with the rest of the program.

Let’s see the difference in one example: suppose you want to calculate a discount, but also use it after the if.

package main

import "fmt"

func main() {
	total := 120
	discount := 0 // declared ahead of time

	if total >= 100 {
		discount = 10 // assignment, NOT declaration
	}

	fmt.Println("discount:", discount) // discount: 10
}

Here discount is declared before the if, because it’s important for us to print it after the condition. Inside the if we don’t create a new variable; we update the existing one.

6. Mini app “BudgetBuddy”: variables and scope

Let’s write a small console app. It will be simple, but useful: we’ll track a budget and expenses. We won’t use functions, collections, or complex structures—only what we already know: input, variables, if, for, and output. It’s like a mini cash register or an expense tracker at the “mom, I’m a programmer” level.

Version 1: read the budget and one purchase

First, we’ll make a very simple version: the user enters a budget and one purchase, and the program prints how much is left.

package main

import "fmt"

func main() {
	var budget int
	var purchase int
	fmt.Scan(&budget, &purchase)

	rest := budget - purchase
	fmt.Println(rest) // for example: 700
}

Notice the style. We read values into variables, then compute rest using :=, because it’s an intermediate result and its type is obvious.

Version 2: a loop over N purchases and why spent must be outside

Now let’s do something more useful: let the user enter the number of purchases n, and then enter n amounts. We need an accumulator spent that lives outside the loop; otherwise, after the loop we won’t be able to use it.

package main

import "fmt"

func main() {
	var budget, n int
	fmt.Scan(&budget, &n)

	spent := 0
	for i := 0; i < n; i++ {
		var x int
		fmt.Scan(&x)
		spent = spent + x
	}
	fmt.Println(budget - spent)
}

Here spent is declared outside the loop because it’s needed after the loop. But x is an internal variable for one iteration: read one purchase, add it to the sum, forget it. This is a good example of “narrow” scope: fewer variables live long—less confusion.

Version 3: budget check with if

Let’s add a condition: if we spent more than the budget, print a warning. Notice that spent lives throughout main, which means it’s available after for and inside if.

package main

import "fmt"

func main() {
	var budget, n int
	fmt.Scan(&budget, &n)

	spent := 0
	for i := 0; i < n; i++ {
		var x int
		fmt.Scan(&x)
		spent = spent + x
	}

	if spent > budget {
		fmt.Println("over budget")
	}
	fmt.Println("spent:", spent)
}

Here we have two important effects. First, spent is declared exactly where it “starts” in meaning—before the loop. Second, the variable x doesn’t spread across the function: it’s needed for 2–3 lines, so it lives for 2–3 lines.

7. Typical mistakes when declaring and using variables

Mistake #1: using = for a name that doesn’t exist yet.
This is one of the most common situations: someone writes sum = 0 because “well, I’m assigning zero”, but they never declared sum anywhere before. In Go, you can’t do that: first declare (var sum int or sum := 0), and only then change (sum = sum + x). A good habit is to train yourself to spot the first encounter with a variable: it must use var or :=.

Mistake #2: expecting a variable from if or for to be available after the block.
Psychologically it’s very understandable: you just computed y, it’s so nice, and you want to use it further. But if y is declared inside {}, then after the closing brace it’s as if it was “deleted”. The solution is simple conceptually: if you need the value after the block, declare the variable before the block and do an assignment inside.

Mistake #3: declaring variables too early and too “wide”.
A beginner sometimes creates ten variables at the beginning of main “just in case”. Then half aren’t used, and the other half are used 40 lines later, and you no longer remember who is who. In Go, it’s much nicer to declare variables closer to where they’re used: this reduces scope and makes the code easier to read (and for your future self, who will look at the code in a week as if it were someone else’s).

Mistake #4: declaring a variable and not using it.
Go is strict about this: if a function has a variable that isn’t used anywhere, the compiler usually complains. At first it’s irritating (“I just wanted it for later!”), but it quickly becomes your ally: it doesn’t let you keep garbage and “forgotten ideas” in the code that confuse the reader. If the variable really isn’t needed—delete it. If it’s needed later—write the code so it actually gets used.

Mistake #5: confusing “declaration” and “update” when reading code.
Sometimes a program “doesn’t work” simply because you think a line creates a new variable, while it only changes the old one (or vice versa). A helpful habit is to read code like a story: “here the variable appeared”, “here its value was changed”, “here we use it”. If you learn to see these three stages, 80% of variable-related problems will disappear without any magic or shamanism.

1
Task
Go SELF, level 6, lesson 1
Locked
Cash and cashback
Cash and cashback
1
Task
Go SELF, level 6, lesson 1
Locked
Checkout discount
Checkout discount
1
Task
Go SELF, level 6, lesson 1
Locked
Sum and Leader
Sum and Leader
1
Task
Go SELF, level 6, lesson 1
Locked
Record Counter
Record Counter
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION