Golang const array: why Go has no constant slices, and what to do instead

Golang const array and golang constant array: Go constants are only numbers, strings, booleans, and complex values built from those—no golang constant slice or const array type; patterns for golang const string array, go const array workarounds, and constant array golang with iota or package-level vars.

Published

Updated

Read time 4 min read

Reviewed byDeepak Prasad

Golang const array: why Go has no constant slices, and what to do instead

Searches like golang const array, golang constant array, go constant array, go const array, const array golang, golang array constant, golang array const, or golang constant slice usually hit the same language rule: const in Go only names compile-time values whose type is a boolean, rune, integer, floating-point, complex, or string (or a typed alias of those), built from constant expressions. A whole array or slice value is never a constant, so const xs = []int{1, 2, 3} and const xs = [3]int{1, 2, 3} both fail to compile. This page explains why, then lists practical patterns—including golang const string array style lists—for data you want to treat as fixed. For general constants, see Effective Go: Constants and the constants blog; for variables and globals; for functions that return data; for slices after you have a backing array.

Tested with Go 1.24 on Linux.


What the compiler allows as const

This is legal:

go
package main

import "fmt"

const (
	piApprox = 355 / 113
	label    = "ready"
	ok       = true
)

func main() {
	fmt.Println(piApprox, label, ok)
}
Output

You should see 3 ready true (integer division in the constant expression).

This is not legal (composite array/slice values are not constants):

text
const nums = [3]int{1, 2, 3} // compile error: not a constant

The same restriction answers golang constant slice: slices are always runtime values built from a pointer, length, and capacity.


golang const string array (one string, many fields)

Keep the list as a const string, then split when you need a []string:

go
package main

import (
	"fmt"
	"strings"
)

const envList = "dev,staging,prod"

func main() {
	fields := strings.Split(envList, ",")
	fmt.Println(fields)
}
Output

You should see [dev staging prod]. The string is constant; the slice is created at runtime and can still be modified—copy with append([]string(nil), fields...) if you want to protect callers from mutation.


go constant array: many const strings, one slice in init

When each entry is its own constant, assemble a []string once in init (still not a const slice, but every element comes from constants):

go
package main

import "fmt"

const (
	envDev  = "dev"
	envProd = "prod"
)

var envs []string

func init() {
	envs = []string{envDev, envProd}
}

func main() {
	fmt.Println(envs)
}
Output

You should see [dev prod]. This fits go constant array–style configs where you want named constants but a single slice to range over.


Fixed array or slice as package-level data (not const)

Use an unexported var plus read-only access through functions if you want to hide mutation, or document that callers must not change shared state:

go
package main

import "fmt"

var defaultPorts = []int{80, 443, 8080}

func Ports() []int {
	out := make([]int, len(defaultPorts))
	copy(out, defaultPorts)
	return out
}

func main() {
	fmt.Println(Ports())
}
Output

You should see [80 443 8080]. Returning a copy avoids sharing the backing array (see append and slice growth for how slices alias memory).


When people want a constant array golang of related numbers or strings, iota blocks are the idiomatic substitute:

go
package main

import "fmt"

const (
	StatusPending = iota
	StatusRunning
	StatusDone
)

func main() {
	fmt.Println(StatusPending, StatusRunning, StatusDone)
}
Output

You should see 0 1 2. Each name is its own const; you still cannot bundle them into a const []int.


Summary

Golang const array and go constant array do not exist as a single const binding: arrays and slices are composite runtime values, so the compiler rejects them in const declarations. Use const strings (plus strings.Split) for a golang const string array feel, build a slice from several const strings in init, use iota for families of related constants, or a package-level var with copying or discipline when you need a fixed list. Arrays remain fixed-length but mutable; const does not make them immutable.


References


Frequently Asked Questions

1. Can I declare a golang const array or golang constant slice?

No; the const keyword cannot name an array or slice type because those composite values are not considered constant in the spec, even if every element is a constant literal.

2. What is the closest thing to a go constant array?

Use separate const values, an iota block for related numbers, a const string you split at init or read time, a package-level var you never mutate by convention, or a small function that returns a fresh copy of a fixed literal each time.

3. How do I model a golang const string array?

Keep one const string such as a comma-separated list and strings.Split into a []string variable at runtime, or declare individual const string lines and build a slice in an init function once.

4. Are Go arrays immutable?

No; array elements are mutable, but the length is fixed. const still cannot apply to the whole array value; only the usual const types apply to const declarations.

5. Why does my const [3]int{1,2,3} fail to compile?

Composite literals of array type are not constant expressions in Go, so the compiler rejects them in a const declaration.
Tuan Nguyen

Data Scientist

Proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise …