github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/types/testdata/examples/types.go (about) 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 var _ = T /* ERROR "cannot use generic type T" */ (0) 106 107 // In type context, generic (parameterized) types cannot be parenthesized before 108 // being instantiated. See also NOTES entry from 12/4/2019. 109 var _ (T /* ERROR "cannot use generic type T" */ )[ /* ERRORx `unexpected \[|expected ';'` */ int] 110 111 // All types may be parameterized, including interfaces. 112 type I1[T any] interface{ 113 m1(T) 114 } 115 116 // There is no such thing as a variadic generic type. 117 type _[T ... /* ERROR "invalid use of '...'" */ any] struct{} 118 119 // Generic interfaces may be embedded as one would expect. 120 type I2 interface { 121 I1(int) // method! 122 I1[string] // embedded I1 123 } 124 125 func _() { 126 var x I2 127 x.I1(0) 128 x.m1("foo") 129 } 130 131 type I0 interface { 132 m0() 133 } 134 135 type I3 interface { 136 I0 137 I1[bool] 138 m(string) 139 } 140 141 func _() { 142 var x I3 143 x.m0() 144 x.m1(true) 145 x.m("foo") 146 } 147 148 type _ struct { 149 ( /* ERROR "cannot parenthesize" */ int8) 150 ( /* ERROR "cannot parenthesize" */ *int16) 151 *( /* ERROR "cannot parenthesize" */ int32) 152 List[int] 153 154 int8 /* ERROR "int8 redeclared" */ 155 *int16 /* ERROR "int16 redeclared" */ 156 List /* ERROR "List redeclared" */ [int] 157 } 158 159 // Issue #45639: We don't allow this anymore. Keep this code 160 // in case we decide to revisit this decision. 161 // 162 // It's possible to declare local types whose underlying types 163 // are type parameters. As with ordinary type definitions, the 164 // types underlying properties are "inherited" but the methods 165 // are not. 166 // func _[T interface{ m(); ~int }]() { 167 // type L T 168 // var x L 169 // 170 // // m is not defined on L (it is not "inherited" from 171 // // its underlying type). 172 // x.m /* ERROR "x.m undefined" */ () 173 // 174 // // But the properties of T, such that as that it supports 175 // // the operations of the types given by its type bound, 176 // // are also the properties of L. 177 // x++ 178 // _ = x - x 179 // 180 // // On the other hand, if we define a local alias for T, 181 // // that alias stands for T as expected. 182 // type A = T 183 // var y A 184 // y.m() 185 // _ = y < 0 186 // } 187 188 // For now, a lone type parameter is not permitted as RHS in a type declaration (issue #45639). 189 // // It is not permitted to declare a local type whose underlying 190 // // type is a type parameter not declared by that type declaration. 191 // func _[T any]() { 192 // type _ T // ERROR "cannot use function type parameter T as RHS in type declaration" 193 // type _ [_ any] T // ERROR "cannot use function type parameter T as RHS in type declaration" 194 // } 195 196 // As a special case, an explicit type argument may be omitted 197 // from a type parameter bound if the type bound expects exactly 198 // one type argument. In that case, the type argument is the 199 // respective type parameter to which the type bound applies. 200 // Note: We may not permit this syntactic sugar at first. 201 // Note: This is now disabled. All examples below are adjusted. 202 type Adder[T any] interface { 203 Add(T) T 204 } 205 206 // We don't need to explicitly instantiate the Adder bound 207 // if we have exactly one type parameter. 208 func Sum[T Adder[T]](list []T) T { 209 var sum T 210 for _, x := range list { 211 sum = sum.Add(x) 212 } 213 return sum 214 } 215 216 // Valid and invalid variations. 217 type B0 any 218 type B1[_ any] any 219 type B2[_, _ any] any 220 221 func _[T1 B0]() {} 222 func _[T1 B1[T1]]() {} 223 func _[T1 B2 /* ERRORx `cannot use generic type .* without instantiation` */ ]() {} 224 225 func _[T1, T2 B0]() {} 226 func _[T1 B1[T1], T2 B1[T2]]() {} 227 func _[T1, T2 B2 /* ERRORx `cannot use generic type .* without instantiation` */ ]() {} 228 229 func _[T1 B0, T2 B1[T2]]() {} // here B1 applies to T2 230 231 // When the type argument is left away, the type bound is 232 // instantiated for each type parameter with that type 233 // parameter. 234 // Note: We may not permit this syntactic sugar at first. 235 func _[A Adder[A], B Adder[B], C Adder[A]]() { 236 var a A // A's type bound is Adder[A] 237 a = a.Add(a) 238 var b B // B's type bound is Adder[B] 239 b = b.Add(b) 240 var c C // C's type bound is Adder[A] 241 a = c.Add(a) 242 } 243 244 // The type of variables (incl. parameters and return values) cannot 245 // be an interface with type constraints or be/embed comparable. 246 type I interface { 247 ~int 248 } 249 250 var ( 251 _ interface /* ERROR "contains type constraints" */ {~int} 252 _ I /* ERROR "contains type constraints" */ 253 ) 254 255 func _(I /* ERROR "contains type constraints" */ ) 256 func _(x, y, z I /* ERROR "contains type constraints" */ ) 257 func _() I /* ERROR "contains type constraints" */ 258 259 func _() { 260 var _ I /* ERROR "contains type constraints" */ 261 } 262 263 type C interface { 264 comparable 265 } 266 267 var _ comparable /* ERROR "comparable" */ 268 var _ C /* ERROR "comparable" */ 269 270 func _(_ comparable /* ERROR "comparable" */ , _ C /* ERROR "comparable" */ ) 271 272 func _() { 273 var _ comparable /* ERROR "comparable" */ 274 var _ C /* ERROR "comparable" */ 275 } 276 277 // Type parameters are never const types, i.e., it's 278 // not possible to declare a constant of type parameter type. 279 // (If a type set contains just a single const type, we could 280 // allow it, but such type sets don't make much sense in the 281 // first place.) 282 func _[T interface{~int|~float64}]() { 283 // not valid 284 const _ = T /* ERROR "not constant" */ (0) 285 const _ T /* ERROR "invalid constant type T" */ = 1 286 287 // valid 288 var _ = T(0) 289 var _ T = 1 290 _ = T(0) 291 } 292 293 // It is possible to create composite literals of type parameter 294 // type as long as it's possible to create a composite literal 295 // of the core type of the type parameter's constraint. 296 func _[P interface{ ~[]int }]() P { 297 return P{} 298 return P{1, 2, 3} 299 } 300 301 func _[P interface{ ~[]E }, E interface{ map[string]P } ]() P { 302 x := P{} 303 return P{{}} 304 return P{E{}} 305 return P{E{"foo": x}} 306 return P{{"foo": x}, {}} 307 } 308 309 // This is a degenerate case with a singleton type set, but we can create 310 // composite literals even if the core type is a defined type. 311 type MyInts []int 312 313 func _[P MyInts]() P { 314 return P{} 315 }