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
Thas a core type, which is the same as the underlying type ofT.An interface
Thas a core type if one of the following conditions is satisfied:
- There is a single type
Uwhich 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 EifTcontains only bidirectional channels, or the typechan<- Eor<-chan Edepending 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 } // []*dataExamples 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 directionsSome operations (slice expressions,
appendandcopy) rely on a slightly more loose form of core types which accept byte slices and strings. Specifically, if there are exactly two types,[]byteandstring, which are the underlying types of all types in the type set of interfaceT, the core type ofTis calledbytestring.Examples of interfaces with
bytestringcore types:interface{ int } // int (same as ordinary core type) interface{ []byte | string } // bytestring interface{ ~[]byte | myString } // bytestringNote that
bytestringis 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