Core types
May 24, 2023
Yesterday we discussed underlying types. Today we’re looking at the somewhat more essoteric concept of a core type. The concept of a core type, as distinct (sometimes) from the underlying type exists for the benefit of some generics-related constructs. This will make more sense as we get to these uses of core types in the future. So for now we’re just going to breeze through the description, without diving into additional detail than what is provided in the spec.
Core types
Each non-interface type
T
has a core type, which is the same as the underlying type ofT
.An interface
T
has a core type if one of the following conditions is satisfied:
- There is a single type
U
which is the underlying type of all types in the type set ofT
; or- the type set of 1 contains only channel types with identical element type
E
, and all directional channels have the same direction.No other interfaces have a core type.
The core type of an interface is, depending on the condition that is satisfied, either:
- the type
U
; or- the type
chan E
ifT
contains only bidirectional channels, or the typechan<- E
or<-chan E
depending on the direction of the directional channels present.By definition, a core type is never a defined type, type parameter, or interface type.
Examples of interfaces with core types:
type Celsius float32 type Kelvin float32 interface{ int } // int interface{ Celsius|Kelvin } // float32 interface{ ~chan int } // chan int interface{ ~chan int|~chan<- int } // chan<- int interface{ ~[]*data; String() string } // []*data
Examples of interfaces without core types:
interface{} // no single underlying type interface{ Celsius|float64 } // no single underlying type interface{ chan int | chan<- string } // channels have different element types interface{ <-chan int | chan<- int } // directional channels have different directions
Some operations (slice expressions,
append
andcopy
) rely on a slightly more loose form of core types which accept byte slices and strings. Specifically, if there are exactly two types,[]byte
andstring
, which are the underlying types of all types in the type set of interfaceT
, the core type ofT
is calledbytestring
.Examples of interfaces with
bytestring
core types:interface{ int } // int (same as ordinary core type) interface{ []byte | string } // bytestring interface{ ~[]byte | myString } // bytestring
Note that
bytestring
is not a real type; it cannot be used to declare variables are[sic*] compose other types. It exists solely to describe the behavior of some operations that read from a sequence of bytes, which may be a byte slice or a string.
*This has been corrected to “or” in the next edition, expected to be published in August with Go 1.21.
Quotes from The Go Programming Language Specification Version of December 15, 2022