Variables & :=

Station 1.1 12 min Interchange: $variables & list() → var

In PHP, a variable springs into existence the first time you assign to it. $platform = 3; and there it is. Assign a string to it later and PHP shrugs: it's a string now.

Go wants a little more ceremony up front, and in return it never lets a variable quietly change what it is.

Three ways to say the same thing

var station string = "Bank" // the full form
var platform = 3            // inferred: int
open := true                // the short form

All three declare a variable. The type always goes after the name, like the function parameters in 0.2.

  • var name type = value is the full version. You'll rarely write all three parts, because Go can see that "Bank" is a string.
  • var name = value drops the type and lets Go infer it.
  • name := value is the short form, and it's what you'll write most of the time. Read := as "declare and assign". It only works inside a function.

There's a fourth shape you'll also see a lot: var name type with no value at all. That gives you the type's zero value, 0, "" or false, exactly as lesson 1.4 describes. No null, no "undefined variable" warning.

Whichever form you use, the type is fixed for good. platform above is an int forever, so platform = "three" is a compile error, not a type juggle. (Lesson 1.3 covers types and converting between them.)

Tip

The convention most Go code follows: use := when you have a value to start with, and var x T when you want the zero value and will fill it in later. At package level, outside any function, var is your only option.

= vs :=

This is the distinction that matters. := declares a new variable. = assigns to one that already exists.

count := 0  // declares count
count = 5   // assigns to it
count := 10 // error: no new variables on left side of :=

There's one wrinkle: := with several names on the left only needs one of them to be new. The others are just assigned. That's handy later, when functions return a value and an error, and you'll meet it constantly in Unit 4.

Swapping without a temp

Several variables can be assigned at once, and Go works out the whole right-hand side before assigning anything. So swapping is one line, no $tmp:

from, to = to, from

That's PHP's [$from, $to] = [$to, $from], minus the throwaway arrays. Check the Interchange tab for both.

Unused is an error

You met this in 0.2: a local variable you declare and never use stops the build with declared and not used: x. If you genuinely need to throw a value away, assign it to the blank identifier, _, which accepts anything and keeps nothing.

14:02debug := true, "just for a second"
14:02declared and not used: debug
14:03_ = debug
14:03(it is now 2031 and that line is still there)
Every Go codebase has one.

Block scope (and the shadow it casts)

A PHP variable belongs to the whole function. Set $status inside an if, and it's still there after the closing brace.

A Go variable belongs to the nearest pair of braces. Declare it inside an if, a loop or a bare { } block, and it's gone at the closing brace. Try to use it afterwards and the compiler says undefined.

That combines with := to produce Go's best-known beginner bug:

origin := "Ealing Broadway"
if reversed {
	origin := "Epping" // a new, inner origin
}
// origin is still "Ealing Broadway" here

Two variables, one name, two scopes:

flowchart TB
  accTitle: Shadowing with := inside an if block
  accDescr: Before the if block, origin is Ealing Broadway. Inside the block, origin := "Epping" declares a second, separate variable that happens to share the name. At the closing brace the inner origin disappears, and the outer one was never touched, so it is still Ealing Broadway.
  o1["origin = Ealing Broadway"] --> blk
  subgraph blk ["Inside if reversed"]
    o2["origin := Epping<br/>a second, new variable"]
  end
  blk -->|"closing brace"| o3["origin is still<br/>Ealing Broadway"]

Mind the gap

:= inside a block shadows the outer variable. In PHP, $origin = 'Epping'; inside the if would update the one you already have. In Go, := inside a new block always declares a fresh variable, even if one with the same name exists outside. The outer one is untouched, and the inner one disappears at the brace. When you mean "update", use =. Here the compiler happens to catch it, because the inner origin is never used. When the inner one is used, it compiles, and the bug ships.

The exercise is exactly this bug, caught by the compiler. Read the error message carefully: it's more helpful than it first looks.

Recap

  • var x T = v, var x = v and x := v all declare a variable. := is the everyday form, but works only inside functions. var x T gives the zero value.
  • A variable's type is fixed when it's declared, whether you write it or Go infers it.
  • := declares, = assigns. a, b = b, a swaps.
  • Unused locals don't compile. _ discards a value.
  • Variables live in their { } block. := in an inner block makes a new variable that shadows the outer one.

1Declaring variables

PHPdeclare.php
<?php
$station = 'Bank';
$platform = 3;
$open = true;

$platform = 'three'; // fine, now a string
GOdeclare.go
var station string = "Bank" // the full form
var platform = 3            // type inferred: int
open := true                // the short form, inside functions

var delay int // no value: starts at 0

platform = "three" // compile error: it's an int

Mind the gap

A Go variable's type is fixed when it's declared. Even when Go infers it, the variable can never hold a value of another type.

2Swapping two values

PHPswap.php
<?php
$from = 'Ealing Broadway';
$to = 'Epping';

[$from, $to] = [$to, $from];
GOswap.go
from := "Ealing Broadway"
to := "Epping"

from, to = to, from

Mind the gap

Plain =, not :=, because both variables already exist. Go evaluates the whole right-hand side before assigning anything, so no temporary variable is needed.

3Block scope

PHPscope.php
<?php
if ($delayed) {
    $status = 'Delayed';
}

echo $status; // works, if $delayed was true
GOscope.go
if delayed {
	status := "Delayed"
}

fmt.Println(status) // compile error: undefined: status

Mind the gap

PHP variables belong to the whole function. Go variables belong to the nearest { } block, so status vanishes at the closing brace.