In Go, a const must be compile-time computable. That doesn’t mean it must be a literal; it can be the result of operations on other constants:
const secondsInMinute = 60
const minutesInHour = 60
const secondsInHour = secondsInMinute * minutesInHour
The compiler can evaluate secondsInMinute * minutesInHour at compile time, so secondsInHour is a valid constant.
Key properties:
- All values in the expression must themselves be constant.
- Only operations that the compiler can fully evaluate at compile time are allowed.
- Types can be explicit (
const x int = 5) or inferred (const x = 5).
What isn't allowed?
Anything that requires information only known at runtime:
// invalid: needs current time at runtime
const now = time.Now()
// invalid: function call that isn't a const expression
const v = math.Sin(0.5)
Even though math.Sin(0.5) is conceptually “pure,” Go doesn’t have a general “const function evaluation” mechanism. Only a small set of built-in operations are allowed in constant expressions (arithmetic, comparisons, shifts, etc. on constants).
Also, you can’t assign a non-constant to a constant:
var x = 10
// const y = x // invalid: x is not a constant
Go’s “untyped” constants
Go has untyped constants:
const x = 5
Here, x doesn’t immediately have a concrete type; it gets one when used:
var a int64 = x // x becomes int64 here
var b float64 = x // x becomes float64 here
This makes numeric constant arithmetic flexible, but only as long as everything stays in the constant world and fits in range.
Comparisons with other languages
Java
finalfields can be either:- Compile-time constants (inlined by the compiler):
static final int X = 5; - Runtime constants:
final LocalDate now = LocalDate.now();
- Compile-time constants (inlined by the compiler):
- Java allows calling methods when initializing
finalvalues, even if they’re not compile-time constants; Go does not forconst.
So:
final int secondsInMinute = 60;
final int minutesInHour = 60;
final int secondsInHour = secondsInMinute * minutesInHour; // valid, but runtime
In Go, the same pattern is compile-time constant.
Java also has enums where constants can be richer objects; Go uses iota with plain consts instead.
C / C++
C:
#defineis a preprocessor macro, purely textual.const int x = 5;is a variable with restricted mutation; whether it’s a true compile-time constant can be subtle (depends on context).
C++:
-
const int x = 5;often behaves like a compile-time constant. -
constexprexplicitly means “must be evaluable at compile time”:constexpr int secondsInMinute = 60; constexpr int minutesInHour = 60; constexpr int secondsInHour = secondsInMinute * minutesInHour; -
C++ can have
constexprfunctions that are evaluated at compile time when used in constant expressions. Go doesn’t have this concept; only built-in operations are allowed inconstexpressions.
JavaScript / TypeScript
JavaScript:
-
constis a read-only binding, not a compile-time constant:const now = new Date(); // perfectly valid -
All evaluation is at runtime; there is no language-level guarantee about compile-time computability.
TypeScript:
- Adds
as constandconst enum, but they’re compile-time TypeScript constructs that vanish after compilation; they don’t behave like Go’sconstin the runtime environment.
So const in JS/TS is mostly about immutability of the variable binding, not about compile-time evaluation.
Rust
Rust has a split similar to Go’s const vs var, but stricter and richer:
-
const– compile-time constants, like Go:const SECONDS_IN_MINUTE: u32 = 60; const MINUTES_IN_HOUR: u32 = 60; const SECONDS_IN_HOUR: u32 = SECONDS_IN_MINUTE * MINUTES_IN_HOUR; -
let– normal variables. -
static– global variables (with optionalmut). -
Rust supports
const fn, functions that can be evaluated in constant expressions, which is more powerful than Go’s constant system.
Caveats in Go
-
No function calls in const expressions (in general)
Except for a few built-ins likelenon strings and some special cases, you can’t call arbitrary functions in aconstexpression. -
Overflow rules are strict
Constant expressions must fit in their destination type:const big = 1 << 100 // var x int64 = big // error: overflows int64 -
No runtime data
You can’t use values derived from input, environment variables, system time, etc. in constants. -
Different from “immutable variable”
Go doesn’t have a way to declare an immutable variable at runtime.constis only for compile-time constants;varis always mutable.