go types 源码

2022-07-15 浏览 (1199)

golang types 代码

文件路径:/src/cmd/compile/internal/types2/testdata/examples/types.go

/ Copyright 2019 The Go Authors. All rights reserved.
/ Use of this source code is governed by a BSD-style
/ license that can be found in the LICENSE file.

/ This file shows some examples of generic types.

package p

/ List is just what it says - a slice of E elements.
type List[E any] []E

/ A generic (parameterized) type must always be instantiated
/ before it can be used to designate the type of a variable
/ (including a struct field, or function parameter); though
/ for the latter cases, the provided type may be another type
/ parameter. So:
var _ List[byte] = []byte{}

/ A generic binary tree might be declared as follows.
type Tree[E any] struct {
	left, right *Tree[E]
	payload E
}

/ A simple instantiation of Tree:
var root1 Tree[int]

/ The actual type parameter provided may be a generic type itself:
var root2 Tree[List[int]]

/ A couple of more complex examples.
/ We don't need extra parentheses around the element type of the slices on
/ the right (unlike when we use ()'s rather than []'s for type parameters).
var _ List[List[int]] = []List[int]{}
var _ List[List[List[Tree[int]]]] = []List[List[Tree[int]]]{}

/ Type parameters act like type aliases when used in generic types
/ in the sense that we can "emulate" a specific type instantiation
/ with type aliases.
type T1[P any] struct {
	f P
}

type T2[P any] struct {
	f struct {
		g P
	}
}

var x1 T1[struct{ g int }]
var x2 T2[int]

func _() {
	/ This assignment is invalid because the types of x1, x2 are T1(...)
	/ and T2(...) respectively, which are two different defined types.
	x1 = x2 / ERROR assignment

	/ This assignment is valid because the types of x1.f and x2.f are
	/ both struct { g int }; the type parameters act like type aliases
	/ and their actual names don't come into play here.
	x1.f = x2.f
}

/ We can verify this behavior using type aliases instead:
type T1a struct {
	f A1
}
type A1 = struct { g int }

type T2a struct {
	f struct {
		g A2
	}
}
type A2 = int

var x1a T1a
var x2a T2a

func _() {
	x1a = x2a / ERROR assignment
	x1a.f = x2a.f
}

/ Another interesting corner case are generic types that don't use
/ their type arguments. For instance:
type T[P any] struct{}

var xint T[int]
var xbool T[bool]

/ Are these two variables of the same type? After all, their underlying
/ types are identical. We consider them to be different because each type
/ instantiation creates a new named type, in this case T<int> and T<bool>
/ even if their underlying types are identical. This is sensible because
/ we might still have methods that have different signatures or behave
/ differently depending on the type arguments, and thus we can't possibly
/ consider such types identical. Consequently:
func _() {
	xint = xbool / ERROR assignment
}

/ Generic types cannot be used without instantiation.
var _ T / ERROR cannot use generic type T
var _ = T /* ERROR cannot use generic type T */ (0)

/ In type context, generic (parameterized) types cannot be parenthesized before
/ being instantiated. See also NOTES entry from 12/4/2019.
var _ (T /* ERROR cannot use generic type T */ )[ /* ERROR unexpected \[ */ int]

/ All types may be parameterized, including interfaces.
type I1[T any] interface{
	m1(T)
}

/ There is no such thing as a variadic generic type.
type _[T ... /* ERROR invalid use of ... */ any] struct{}

/ Generic interfaces may be embedded as one would expect.
type I2 interface {
	I1(int)     / method!
	I1[string]  / embedded I1
}

func _() {
	var x I2
	x.I1(0)
	x.m1("foo")
}

type I0 interface {
	m0()
}

type I3 interface {
	I0
	I1[bool]
	m(string)
}

func _() {
	var x I3
	x.m0()
	x.m1(true)
	x.m("foo")
}

type _ struct {
	( /* ERROR cannot parenthesize */ int8)
	( /* ERROR cannot parenthesize */ *int16)
	*( /* ERROR cannot parenthesize */ int32)
	List[int]

	int8 /* ERROR int8 redeclared */
	* /* ERROR int16 redeclared */ int16
	List /* ERROR List redeclared */ [int]
}

/ Issue #45639: We don't allow this anymore. Keep this code
/               in case we decide to revisit this decision.
/
/ It's possible to declare local types whose underlying types
/ are type parameters. As with ordinary type definitions, the
/ types underlying properties are "inherited" but the methods
/ are not.
/ func _[T interface{ m(); ~int }]() {
/ 	type L T
/ 	var x L
/ 
/ 	/ m is not defined on L (it is not "inherited" from
/ 	/ its underlying type).
/ 	x.m /* ERROR x.m undefined */ ()
/ 
/ 	/ But the properties of T, such that as that it supports
/ 	/ the operations of the types given by its type bound,
/ 	/ are also the properties of L.
/ 	x++
/ 	_ = x - x
/ 
/ 	/ On the other hand, if we define a local alias for T,
/ 	/ that alias stands for T as expected.
/ 	type A = T
/ 	var y A
/ 	y.m()
/ 	_ = y < 0
/ }

/ For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639).
/ / It is not permitted to declare a local type whose underlying
/ / type is a type parameter not declared by that type declaration.
/ func _[T any]() {
/ 	type _ T         / ERROR cannot use function type parameter T as RHS in type declaration
/ 	type _ [_ any] T / ERROR cannot use function type parameter T as RHS in type declaration
/ }

/ As a special case, an explicit type argument may be omitted
/ from a type parameter bound if the type bound expects exactly
/ one type argument. In that case, the type argument is the
/ respective type parameter to which the type bound applies.
/ Note: We may not permit this syntactic sugar at first.
/ Note: This is now disabled. All examples below are adjusted.
type Adder[T any] interface {
	Add(T) T
}

/ We don't need to explicitly instantiate the Adder bound
/ if we have exactly one type parameter.
func Sum[T Adder[T]](list []T) T {
	var sum T
	for _, x := range list {
		sum = sum.Add(x)
	}
	return sum
}

/ Valid and invalid variations.
type B0 any
type B1[_ any] any
type B2[_, _ any] any

func _[T1 B0]() {}
func _[T1 B1[T1]]() {}
func _[T1 B2 /* ERROR cannot use generic type .* without instantiation */ ]() {}

func _[T1, T2 B0]() {}
func _[T1 B1[T1], T2 B1[T2]]() {}
func _[T1, T2 B2 /* ERROR cannot use generic type .* without instantiation */ ]() {}

func _[T1 B0, T2 B1[T2]]() {} / here B1 applies to T2

/ When the type argument is left away, the type bound is
/ instantiated for each type parameter with that type
/ parameter.
/ Note: We may not permit this syntactic sugar at first.
func _[A Adder[A], B Adder[B], C Adder[A]]() {
	var a A / A's type bound is Adder[A]
	a = a.Add(a)
	var b B / B's type bound is Adder[B]
	b = b.Add(b)
	var c C / C's type bound is Adder[A]
	a = c.Add(a)
}

/ The type of variables (incl. parameters and return values) cannot
/ be an interface with type constraints or be/embed comparable.
type I interface {
	~int
}

var (
	_ interface /* ERROR contains type constraints */ {~int}
	_ I /* ERROR contains type constraints */
)

func _(I /* ERROR contains type constraints */ )
func _(x, y, z I /* ERROR contains type constraints */ )
func _() I /* ERROR contains type constraints */

func _() {
	var _ I /* ERROR contains type constraints */
}

type C interface {
	comparable
}

var _ comparable /* ERROR comparable */
var _ C /* ERROR comparable */

func _(_ comparable /* ERROR comparable */ , _ C /* ERROR comparable */ )

func _() {
	var _ comparable /* ERROR comparable */
	var _ C /* ERROR comparable */
}

/ Type parameters are never const types, i.e., it's
/ not possible to declare a constant of type parameter type.
/ (If a type set contains just a single const type, we could
/ allow it, but such type sets don't make much sense in the
/ first place.)
func _[T interface{~int|~float64}]() {
	/ not valid
	const _ = T /* ERROR not constant */ (0)
	const _ T /* ERROR invalid constant type T */ = 1

	/ valid
	var _ = T(0)
	var _ T = 1
	_ = T(0)
}

/ It is possible to create composite literals of type parameter
/ type as long as it's possible to create a composite literal
/ of the core type of the type parameter's constraint.
func _[P interface{ ~[]int }]() P {
	return P{}
	return P{1, 2, 3}
}

func _[P interface{ ~[]E }, E interface{ map[string]P } ]() P {
	x := P{}
	return P{{}}
	return P{E{}}
	return P{E{"foo": x}}
	return P{{"foo": x}, {}}
}

/ This is a degenerate case with a singleton type set, but we can create
/ composite literals even if the core type is a defined type.
type MyInts []int

func _[P MyInts]() P {
	return P{}
}

相关信息

go 源码目录

相关文章

go constraints 源码

go functions 源码

go inference 源码

go methods 源码

go operations 源码

go typesets 源码

^