Constants

Constants are fixed at compile time, and an untyped constant adapts to whatever type the place it is used needs.

Syntaxconst name = value // or, to fix the type: const name Type = value

A constant is a value with a name that can never change. You declare it with const. The compiler works out its value while building the program, so there is nothing to compute and nothing to change while the program runs.

Typed and untyped

const timeout int = 30 is a typed constant. It is an int and can only be used where an int fits. const maxMB = 25 is an untyped constant. It has a kind, in this case an integer, but no fixed type until it is used. The same untyped constant can start an int in one line and a float64 in the next. That flexibility is the reason to leave the type off by default. If an untyped constant is used somewhere that needs no particular type, it falls back to its default type: int for whole numbers, float64 for numbers with a decimal point, string for quoted text, bool for true and false.

Constant expressions

A constant may be built from other constants, as long as the compiler can work the whole thing out: const maxBytes = maxMB * 1024 * 1024. len of a constant string is also constant. A call to a function that reads a file is not, so it cannot define a constant.

What trips people up

The set of possible constants is narrow. Overflow is caught while compiling, not at run time, which is a benefit: var b int8 = 300 never builds.

Example

Example · go
package main

import "fmt"

// An untyped constant has no fixed type until it is used.
const maxUploadMB = 25

// A typed constant is an int everywhere, for ever.
const timeoutSeconds int = 30

func main() {
	var asInt int = maxUploadMB
	var asFloat float64 = maxUploadMB // the same constant, a different type
	fmt.Println(asInt, asFloat)

	// The compiler works this out while building. Nothing is multiplied
	// while the program runs.
	const maxUploadBytes = maxUploadMB * 1024 * 1024
	fmt.Println(maxUploadBytes)

	var seconds int = timeoutSeconds
	fmt.Println(seconds)

	// len of a constant string is itself a constant.
	const nameLen = len("soundscode")
	fmt.Println(nameLen)
}

// Output:
// 25 25
// 26214400
// 30
// 10

When to use it

  • Fixing a page size or an upload limit that must not change while the service runs.
  • Naming a magic number in a formula so the next reader knows what it means.
  • Defining a byte-size unit that is used in both integer and floating-point arithmetic.
  • Catching an out-of-range value at build time instead of shipping it.

More examples

One untyped constant, several types

This is why math.Pi in the standard library is an untyped constant: it drops into float32 and float64 arithmetic without a conversion. Define your own numeric constants the same way unless you have a reason to pin the type.

Example · go
package main

import "fmt"

// Untyped: a float kind, but not yet a float32 or a float64.
const half = 0.5

// Untyped, and with no fractional part, so it also fits an int.
const two = 2.0

func main() {
	var f32 float32 = half
	var f64 float64 = half
	var n int = two

	fmt.Println(f32, f64, n)
}

// Output:
// 0.5 0.5 2

A typed constant refuses other types

Write the type on a constant when you want that restriction, for example a constant of your own named type so it cannot be mixed with plain numbers. Leave it off when the constant is a plain quantity used in several numeric types.

Example · go
package main

import "fmt"

const limit int = 100

func main() {
	// var wrong int8 = limit
	// compile error: cannot use limit (constant 100 of type int) as int8 value

	// An untyped literal of the same size is fine, because it has no type yet.
	var small int8 = 100

	// A typed constant needs an explicit conversion to change type.
	var ratio = float64(limit) / 3

	fmt.Println(small)
	fmt.Printf("%.2f\n", ratio)
}

// Output:
// 100
// 33.33

A block of named limits

Reach for this instead of scattering 50 and 2 through the code as bare numbers. The names explain the intent, and because they are constants nothing at run time can change them, which is a different guarantee from a package-level var.

Example · go
package api

// Grouping constants documents the knobs of a package in one place.
const (
	appName    = "soundscode"
	apiVersion = "v1"
	perPage    = 50
	maxBodyMB  = 2
)

Discussion

  • Be the first to comment on this lesson.