Black Lives Matter. Support the Equal Justice Initiative.

Text file src/go/types/testdata/examples/types.go2

Documentation: go/types/testdata/examples

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // This file shows some examples of generic types.
     6  
     7  package p
     8  
     9  // List is just what it says - a slice of E elements.
    10  type List[E any] []E
    11  
    12  // A generic (parameterized) type must always be instantiated
    13  // before it can be used to designate the type of a variable
    14  // (including a struct field, or function parameter); though
    15  // for the latter cases, the provided type may be another type
    16  // parameter. So:
    17  var _ List[byte] = []byte{}
    18  
    19  // A generic binary tree might be declared as follows.
    20  type Tree[E any] struct {
    21  	left, right *Tree[E]
    22  	payload E
    23  }
    24  
    25  // A simple instantiation of Tree:
    26  var root1 Tree[int]
    27  
    28  // The actual type parameter provided may be a generic type itself:
    29  var root2 Tree[List[int]]
    30  
    31  // A couple of more complex examples.
    32  // We don't need extra parentheses around the element type of the slices on
    33  // the right (unlike when we use ()'s rather than []'s for type parameters).
    34  var _ List[List[int]] = []List[int]{}
    35  var _ List[List[List[Tree[int]]]] = []List[List[Tree[int]]]{}
    36  
    37  // Type parameters act like type aliases when used in generic types
    38  // in the sense that we can "emulate" a specific type instantiation
    39  // with type aliases.
    40  type T1[P any] struct {
    41  	f P
    42  }
    43  
    44  type T2[P any] struct {
    45  	f struct {
    46  		g P
    47  	}
    48  }
    49  
    50  var x1 T1[struct{ g int }]
    51  var x2 T2[int]
    52  
    53  func _() {
    54  	// This assignment is invalid because the types of x1, x2 are T1(...)
    55  	// and T2(...) respectively, which are two different defined types.
    56  	x1 = x2 // ERROR assignment
    57  
    58  	// This assignment is valid because the types of x1.f and x2.f are
    59  	// both struct { g int }; the type parameters act like type aliases
    60  	// and their actual names don't come into play here.
    61  	x1.f = x2.f
    62  }
    63  
    64  // We can verify this behavior using type aliases instead:
    65  type T1a struct {
    66  	f A1
    67  }
    68  type A1 = struct { g int }
    69  
    70  type T2a struct {
    71  	f struct {
    72  		g A2
    73  	}
    74  }
    75  type A2 = int
    76  
    77  var x1a T1a
    78  var x2a T2a
    79  
    80  func _() {
    81  	x1a = x2a // ERROR assignment
    82  	x1a.f = x2a.f
    83  }
    84  
    85  // Another interesting corner case are generic types that don't use
    86  // their type arguments. For instance:
    87  type T[P any] struct{}
    88  
    89  var xint T[int]
    90  var xbool T[bool]
    91  
    92  // Are these two variables of the same type? After all, their underlying
    93  // types are identical. We consider them to be different because each type
    94  // instantiation creates a new named type, in this case T<int> and T<bool>
    95  // even if their underlying types are identical. This is sensible because
    96  // we might still have methods that have different signatures or behave
    97  // differently depending on the type arguments, and thus we can't possibly
    98  // consider such types identical. Consequently:
    99  func _() {
   100  	xint = xbool // ERROR assignment
   101  }
   102  
   103  // Generic types cannot be used without instantiation.
   104  var _ T // ERROR cannot use generic type T
   105  
   106  // In type context, generic (parameterized) types cannot be parenthesized before
   107  // being instantiated. See also NOTES entry from 12/4/2019.
   108  var _ (T /* ERROR cannot use generic type T */ )[ /* ERROR expected ';' */ int]
   109  
   110  // All types may be parameterized, including interfaces.
   111  type I1[T any] interface{
   112  	m1(T)
   113  }
   114  
   115  // There is no such thing as a variadic generic type.
   116  type _[T ... /* ERROR invalid use of ... */ interface{}] struct{}
   117  
   118  // Generic interfaces may be embedded as one would expect.
   119  type I2 interface {
   120  	I1(int)     // method!
   121  	I1[string]  // embedded I1
   122  }
   123  
   124  func _() {
   125  	var x I2
   126  	x.I1(0)
   127  	x.m1("foo")
   128  }
   129  
   130  type I0 interface {
   131  	m0()
   132  }
   133  
   134  type I3 interface {
   135  	I0
   136  	I1[bool]
   137  	m(string)
   138  }
   139  
   140  func _() {
   141  	var x I3
   142  	x.m0()
   143  	x.m1(true)
   144  	x.m("foo")
   145  }
   146  
   147  // We accept parenthesized embedded struct fields so we can distinguish between
   148  // a named field with a parenthesized type foo (T) and an embedded parameterized
   149  // type (foo(T)), similarly to interface embedding.
   150  // They still need to be valid embedded types after the parentheses are stripped
   151  // (i.e., in contrast to interfaces, we cannot embed a struct literal). The name
   152  // of the embedded field is derived as before, after stripping parentheses.
   153  // (7/14/2020: See comment above. We probably will revert this generalized ability
   154  // if we go with [] for type parameters.)
   155  type _ struct {
   156  	int8
   157  	*int16
   158  	*List[int]
   159  
   160  	int8 /* ERROR int8 redeclared */
   161  	* /* ERROR List redeclared */ List[int]
   162  }
   163  
   164  // It's possible to declare local types whose underlying types
   165  // are type parameters. As with ordinary type definitions, the
   166  // types underlying properties are "inherited" but the methods
   167  // are not.
   168  func _[T interface{ m(); type int }]() {
   169  	type L T
   170  	var x L
   171  
   172  	// m is not defined on L (it is not "inherited" from
   173  	// its underlying type).
   174  	x.m /* ERROR x.m undefined */ ()
   175  
   176  	// But the properties of T, such that as that it supports
   177  	// the operations of the types given by its type bound,
   178  	// are also the properties of L.
   179  	x++
   180  	_ = x - x
   181  
   182  	// On the other hand, if we define a local alias for T,
   183  	// that alias stands for T as expected.
   184  	type A = T
   185  	var y A
   186  	y.m()
   187  	_ = y < 0
   188  }
   189  
   190  // As a special case, an explicit type argument may be omitted
   191  // from a type parameter bound if the type bound expects exactly
   192  // one type argument. In that case, the type argument is the
   193  // respective type parameter to which the type bound applies.
   194  // Note: We may not permit this syntactic sugar at first.
   195  // Note: This is now disabled. All examples below are adjusted.
   196  type Adder[T any] interface {
   197  	Add(T) T
   198  }
   199  
   200  // We don't need to explicitly instantiate the Adder bound
   201  // if we have exactly one type parameter.
   202  func Sum[T Adder[T]](list []T) T {
   203  	var sum T
   204  	for _, x := range list {
   205  		sum = sum.Add(x)
   206  	}
   207  	return sum
   208  }
   209  
   210  // Valid and invalid variations.
   211  type B0 interface {}
   212  type B1[_ any] interface{}
   213  type B2[_, _ any] interface{}
   214  
   215  func _[T1 B0]()
   216  func _[T1 B1[T1]]()
   217  func _[T1 B2 /* ERROR cannot use generic type .* without instantiation */ ]()
   218  
   219  func _[T1, T2 B0]()
   220  func _[T1 B1[T1], T2 B1[T2]]()
   221  func _[T1, T2 B2 /* ERROR cannot use generic type .* without instantiation */ ]()
   222  
   223  func _[T1 B0, T2 B1[T2]]() // here B1 applies to T2
   224  
   225  // When the type argument is left away, the type bound is
   226  // instantiated for each type parameter with that type
   227  // parameter.
   228  // Note: We may not permit this syntactic sugar at first.
   229  func _[A Adder[A], B Adder[B], C Adder[A]]() {
   230  	var a A // A's type bound is Adder[A]
   231  	a = a.Add(a)
   232  	var b B // B's type bound is Adder[B]
   233  	b = b.Add(b)
   234  	var c C // C's type bound is Adder[A]
   235  	a = c.Add(a)
   236  }
   237  
   238  // The type of variables (incl. parameters and return values) cannot
   239  // be an interface with type constraints or be/embed comparable.
   240  type I interface {
   241  	type int
   242  }
   243  
   244  var (
   245  	_ interface /* ERROR contains type constraints */ {type int}
   246  	_ I /* ERROR contains type constraints */
   247  )
   248  
   249  func _(I /* ERROR contains type constraints */ )
   250  func _(x, y, z I /* ERROR contains type constraints */ )
   251  func _() I /* ERROR contains type constraints */
   252  
   253  func _() {
   254  	var _ I /* ERROR contains type constraints */
   255  }
   256  
   257  type C interface {
   258  	comparable
   259  }
   260  
   261  var _ comparable /* ERROR comparable */
   262  var _ C /* ERROR comparable */
   263  
   264  func _(_ comparable /* ERROR comparable */ , _ C /* ERROR comparable */ )
   265  
   266  func _() {
   267  	var _ comparable /* ERROR comparable */
   268  	var _ C /* ERROR comparable */
   269  }
   270  
   271  // Type parameters are never const types, i.e., it's
   272  // not possible to declare a constant of type parameter type.
   273  // (If a type list contains just a single const type, we could
   274  // allow it, but such type lists don't make much sense in the
   275  // first place.)
   276  func _[T interface { type int, float64 }]() {
   277  	// not valid
   278  	const _ = T /* ERROR not constant */ (0)
   279  	const _ T /* ERROR invalid constant type T */ = 1
   280  
   281  	// valid
   282  	var _ = T(0)
   283  	var _ T = 1
   284  	_ = T(0)
   285  }
   286  
   287  

View as plain text