mirror of
https://github.com/golang/go
synced 2024-09-05 16:04:50 +00:00
spec: add type parameter lists
Change-Id: I29e9188a0fa1326c2755a9b86aeb47feaa8019be Reviewed-on: https://go-review.googlesource.com/c/go/+/365274 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
91abe4be0e
commit
0c3b4a358a
197
doc/go_spec.html
197
doc/go_spec.html
|
@ -1,6 +1,6 @@
|
|||
<!--{
|
||||
"Title": "The Go Programming Language Specification - Go 1.18 Draft (incomplete)",
|
||||
"Subtitle": "Version of Nov 18, 2021",
|
||||
"Subtitle": "Version of Nov 19, 2021",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
|
@ -849,8 +849,7 @@ Every type has a (possibly empty) method set associated with it:
|
|||
</li>
|
||||
|
||||
<li>
|
||||
The method set of a <a href="#Pointer_types">pointer</a> <code>*T</code>
|
||||
to a defined type <code>T</code>
|
||||
The method set of a pointer to a defined type <code>T</code>
|
||||
(where <code>T</code> is neither a pointer nor an interface)
|
||||
is the set of all methods declared with receiver <code>*T</code> or <code>T</code>.
|
||||
</li>
|
||||
|
@ -2246,12 +2245,12 @@ type (
|
|||
|
||||
<p>
|
||||
A type definition creates a new, distinct type with the same
|
||||
<a href="#Types">underlying type</a> and operations as the given type,
|
||||
and binds an identifier to it.
|
||||
<a href="#Types">underlying type</a> and operations as the given type
|
||||
and binds an identifier, the <i>type name</i>, to it.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
TypeDef = identifier Type .
|
||||
TypeDef = identifier [ TypeParameters ] Type .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
|
@ -2328,6 +2327,130 @@ func (tz TimeZone) String() string {
|
|||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the type definition specifies <a href="#Type_parameter_lists">type parameters</a>,
|
||||
the type name denotes a <i>parameterized type</i>.
|
||||
Parameterized types must be <a href="#Instantiations">instantiated</a> when they
|
||||
are used.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type List[T any] struct {
|
||||
next *List[T]
|
||||
value T
|
||||
}
|
||||
|
||||
type Tree[T constraints.Ordered] struct {
|
||||
left, right *Tree[T]
|
||||
value T
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The given type cannot be a type parameter in a type definition.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type T[P any] P // illegal: P is a type parameter
|
||||
|
||||
func f[T any]() {
|
||||
type L T // illegal: T is a type parameter declared by the enclosing function
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A parameterized type may also have methods associated with it. In this case,
|
||||
the method receivers must declare the same number of type parameters as
|
||||
present in the parameterized type definition.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
// The method Len returns the number of elements in the linked list l.
|
||||
func (l *List[T]) Len() int { … }
|
||||
</pre>
|
||||
|
||||
<h3 id="Type_parameter_lists">Type parameter lists</h3>
|
||||
|
||||
<p>
|
||||
A type parameter list declares the <a href="#Type_parameters">type parameters</a>
|
||||
in a type-parameterized function or type declaration.
|
||||
The type parameter list looks like an ordinary <a href="#Function_types">function parameter list</a>
|
||||
except that the type parameter names must all be present and the list is enclosed
|
||||
in square brackets rather than parentheses.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
TypeParameters = "[" TypeParamList [ "," ] "]" .
|
||||
TypeParamList = TypeParamDecl { "," TypeParamDecl } .
|
||||
TypeParamDecl = IdentifierList TypeConstraint .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Each identifier declares a type parameter.
|
||||
All non-blank names in the list must be unique.
|
||||
Each type parameter is a new and different <a href="#Types">named type</a>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
[P any]
|
||||
[S interface{ ~[]byte|string }]
|
||||
[S ~[]E, E any]
|
||||
[P Constraint[int]]
|
||||
[_ any]
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Just as each ordinary function parameter has a parameter type, each type parameter
|
||||
has a corresponding (meta-)type which is called its
|
||||
<a href="#Type_constraints"><i>type constraint</i></a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A parsing ambiguity arises when the type parameter list for a parameterized type
|
||||
declares a single type parameter with a type constraint of the form <code>*C</code>
|
||||
or <code>(C)</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type T[P *C] …
|
||||
type T[P (C)] …
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In these rare cases, the type parameter declaration is indistinguishable from
|
||||
the expressions <code>P*C</code> or <code>P(C)</code> and the type declaration
|
||||
is parsed as an array type declaration.
|
||||
To resolve the ambiguity, embed the constraint in an interface:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type T[P interface{*C}] …
|
||||
</pre>
|
||||
|
||||
<h4 id="Type_constraints">Type constraints</h4>
|
||||
|
||||
<p>
|
||||
A type constraint is an <a href="#Interface_types">interface</a> that determines the
|
||||
set of permissible type arguments for the respective type parameter and controls the
|
||||
operations supported by values of that type parameter.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
TypeConstraint = TypeElem .
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
If the constraint is an interface literal containing exactly one embedded type element
|
||||
<code>interface{E}</code>, in a type parameter list the enclosing <code>interface{ … }</code>
|
||||
may be omitted for convenience:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
[T *P] // = [T interface{*P}]
|
||||
[T ~int] // = [T interface{~int}]
|
||||
[T int|string] // = [T interface{int|string}]
|
||||
type Constraint ~int // illegal: ~int is not inside a type parameter list
|
||||
</pre>
|
||||
|
||||
<h3 id="Variable_declarations">Variable declarations</h3>
|
||||
|
||||
|
@ -2437,13 +2560,19 @@ they can be used to declare local temporary variables.
|
|||
|
||||
<h3 id="Function_declarations">Function declarations</h3>
|
||||
|
||||
<!--
|
||||
Given the importance of functions, this section has always
|
||||
been woefully underdeveloped. Would be nice to expand this
|
||||
a bit.
|
||||
-->
|
||||
|
||||
<p>
|
||||
A function declaration binds an identifier, the <i>function name</i>,
|
||||
to a function.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
FunctionDecl = "func" FunctionName Signature [ FunctionBody ] .
|
||||
FunctionDecl = "func" FunctionName [ TypeParameters ] Signature [ FunctionBody ] .
|
||||
FunctionName = identifier .
|
||||
FunctionBody = Block .
|
||||
</pre>
|
||||
|
@ -2466,18 +2595,28 @@ func IndexRune(s string, r rune) int {
|
|||
</pre>
|
||||
|
||||
<p>
|
||||
A function declaration may omit the body. Such a declaration provides the
|
||||
signature for a function implemented outside Go, such as an assembly routine.
|
||||
If the function declaration specifies <a href="#Type_parameter_lists">type parameters</a>,
|
||||
the function name denotes a <i>type-parameterized function</i>.
|
||||
Type-parameterized functions must be <a href="#Instantiations">instantiated</a> when they
|
||||
are used.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func min(x int, y int) int {
|
||||
func min[T constraints.Ordered](x, y T) T {
|
||||
if x < y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A function declaration without type parameters may omit the body.
|
||||
Such a declaration provides the signature for a function implemented outside Go,
|
||||
such as an assembly routine.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func flushICache(begin, end uintptr) // implemented externally
|
||||
</pre>
|
||||
|
||||
|
@ -2498,9 +2637,10 @@ Receiver = Parameters .
|
|||
The receiver is specified via an extra parameter section preceding the method
|
||||
name. That parameter section must declare a single non-variadic parameter, the receiver.
|
||||
Its type must be a <a href="#Type_definitions">defined</a> type <code>T</code> or a
|
||||
pointer to a defined type <code>T</code>. <code>T</code> is called the receiver
|
||||
<i>base type</i>. A receiver base type cannot be a pointer or interface type and
|
||||
it must be defined in the same package as the method.
|
||||
pointer to a defined type <code>T</code>, possibly followed by a list of type parameter
|
||||
names <code>[P1, P2, …]</code> enclosed in square brackets.
|
||||
<code>T</code> is called the receiver <i>base type</i>. A receiver base type cannot be
|
||||
a pointer or interface type and it must be defined in the same package as the method.
|
||||
The method is said to be <i>bound</i> to its receiver base type and the method name
|
||||
is visible only within <a href="#Selectors">selectors</a> for type <code>T</code>
|
||||
or <code>*T</code>.
|
||||
|
@ -2542,19 +2682,33 @@ to the base type <code>Point</code>.
|
|||
</p>
|
||||
|
||||
<p>
|
||||
The type of a method is the type of a function with the receiver as first
|
||||
argument. For instance, the method <code>Scale</code> has type
|
||||
If the receiver base type is a <a href="#Type_declarations">parameterized type</a>, the
|
||||
receiver specification must declare corresponding type parameters for the method
|
||||
to use. This makes the receiver type parameters available to the method.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Syntactically, this type parameter declaration looks like an
|
||||
<a href="#Instantiantions">instantiation</a> of the receiver base type, except that
|
||||
the type arguments are the type parameters being declared, one for each type parameter
|
||||
of the receiver base type.
|
||||
The type parameter names do not need to match their corresponding parameter names in the
|
||||
receiver base type definition, and all non-blank parameter names must be unique in the
|
||||
receiver parameter section and the method signature.
|
||||
The receiver type parameter constraints are implied by the receiver base type definition:
|
||||
corresponding type parameters have corresponding constraints.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func(p *Point, factor float64)
|
||||
type Pair[A, B any] struct {
|
||||
a A
|
||||
b B
|
||||
}
|
||||
|
||||
func (p Pair[A, B]) Swap() Pair[A, B] { return Pair[A, B]{p.b, p.a} }
|
||||
func (p Pair[First, _]) First() First { return p.a }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
However, a function declared this way is not a method.
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="Expressions">Expressions</h2>
|
||||
|
||||
<p>
|
||||
|
@ -2823,6 +2977,7 @@ noteFrequency := map[string]float32{
|
|||
|
||||
<p>
|
||||
A function literal represents an anonymous <a href="#Function_declarations">function</a>.
|
||||
Function literals cannot declare type parameters.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
|
|
Loading…
Reference in a new issue