Short Variable Declarations

The := form declares and assigns in one step, works only inside functions, and needs at least one new name.

Syntaxname := value // identical to: var name = value

Inside a function, Go offers a shorter way to make a variable: :=. It declares the variable and gives it a value in one step.

The short form and the long form are the same thing

b := 2 and var b = 2 produce exactly the same variable. The short form is the long form with the word var and the type left out; the compiler infers the type from the value in both cases. Neither is faster or safer. Most Go code inside functions uses :=, so you need to read both and write both.

Two rules

  1. It only works inside a function. At the top level of a file there is no function, so a package-level variable must use var.
  2. At least one name on the left of := must be new. If every name already exists in that block, use plain = instead, which is assignment.

That second rule is what makes := comfortable for several values at once. name, n := "gadget", 4 is legal when n is new even if name is not: n is declared and name is simply assigned.

What trips people up

Using := where nothing is new gives "no new variables on left side of :=". The other trap is quieter. Inside a new block, := always makes a brand new variable, even when the same name exists outside. The outer one keeps its old value and nothing warns you.

Example

Example · go
package main

import "fmt"

func main() {
	// These two lines declare the same kind of variable.
	// The first is the long form, the second is the short form.
	var a = 2
	b := 2

	// Two names at once. Each type is inferred from its own value.
	name, size := "widget", 3

	// n is new on this line, so := is allowed.
	// name already exists, so it is only assigned a new value.
	name, n := "gadget", 4

	fmt.Println(a, b)
	fmt.Println(name, size, n)
}

// Output:
// 2 2
// gadget 3 4

When to use it

  • Naming the two results of a call, such as a parsed number and its error, on one line.
  • Giving an intermediate calculation a name so the next line reads clearly.
  • Overwriting a default with a value read at startup, using plain = instead of :=.
  • Reading a value out of a map while also asking whether the key was present.

More examples

Taking two results from one call

This is the commonest use of := in real Go: one line that names both a result and the error that reports whether producing it worked. Later lessons cover what to do with that error. The signature is func Atoi(s string) (int, error).

Example · go
package main

import (
	"fmt"
	"strconv"
)

func main() {
	// strconv.Atoi turns text into a number. It hands back two values:
	// the number, and an error value that reports failure.
	// Nothing fails here, so err is nil, which means "no error".
	n, err := strconv.Atoi("42")
	fmt.Println(n, err)

	// Text that is not a number fills the error and leaves the number at 0.
	bad, badErr := strconv.Atoi("x42")
	fmt.Println(bad, badErr != nil)
}

// Output:
// 42 <nil>
// 0 true

At the top level of a file, var is the only option

Every file has some declarations outside any function, and := is not available there. Keep this in mind when you move a line out of a function and into package scope: the := has to become a var.

Example · go
package config

// version := "1.0"
// The line above does not compile:
// syntax error: non-declaration statement outside function body

// Package-level variables need the long form.
var version = "1.0"

// Grouping works the same way at the top level.
var (
	host = "localhost"
	port = 8080
)

When no name is new

Reach for this when you are overwriting values you already declared, for example replacing a default with something read from the environment. The compiler error names the exact problem, and the fix is always to drop the colon.

Example · go
package main

import "fmt"

func main() {
	host, port := "localhost", 8080

	// host, port := "example.com", 443
	// compile error: no new variables on left side of :=

	// Plain = assigns to both existing variables.
	host, port = "example.com", 443

	fmt.Println(host, port)
}

// Output:
// example.com 443

Discussion

  • Be the first to comment on this lesson.