Underlying types

May 23, 2023

We’ve made it through the complete list of types in Go. Now we’re going to dig into some of the fundamentals, with a tour of general “Properties of types and values”.

Properties of types and values

Underlying types

Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T’s underlying type is the underlying type of the type to which T refers in its declaration. For a type parameter that is the underlying type of its type constraint, which is always an interface.

type (
	A1 = string
	A2 = A1
)

type (
	B1 string
	B2 B1
	B3 []B1
	B4 B3
)

func f[P any](x P) { … }

The underlying type of string, A1, A2, B1, and B2 is string. The underlying type of []B1, B3, and B4 is []B1. The underlying type of P is interface{}.

So this all seems pretty straight forward. But who cares?

The underlying type is used in type conversions, which we’ll cover in greater detail later on. But the TL;DR; verion is that types that share an underlying type can be converted directly.

x := string("foo")
y = A1(x)
fmt.Println(x, y) // Prints: foo foo

Automatic conversion can also happen when passing arguments to functions which accept arguments of the same underlying type:

func display(x string) {
	fmt.Println(x)
}

x := A1("bar")
display(x) // Prints: bar

Although display() takes an argument of type A1, and not string, because they share the same underlying type, conversion happens automatically.

Quotes from The Go Programming Language Specification Version of December 15, 2022

Share this