mirror of
https://github.com/golang/go
synced 2024-11-24 21:10:04 -07:00
doc/go1: most of the simple language changes
R=rsc, adg, r CC=golang-dev https://golang.org/cl/5477044
This commit is contained in:
parent
27cab90363
commit
136c04f71a
226
doc/go1.html
226
doc/go1.html
@ -31,17 +31,92 @@ r60 to compile and run under Go 1. Finally, it outlines the new
|
||||
<code>go</code> command for building Go programs and the new binary
|
||||
release process being introduced. Most of these topics have more
|
||||
thorough presentations elsewhere; such documents are linked below.
|
||||
</p>
|
||||
|
||||
<h2 id="language">Changes to the language</h2>
|
||||
|
||||
<h3 id="append">Append</h3>
|
||||
|
||||
<p>
|
||||
The <code>append</code> built-in function is variadic, so one can
|
||||
append to a byte slice using the <code>...</code> syntax in the
|
||||
call.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/greeting := ..byte/` `/append.*hello/`}}
|
||||
--> greeting := []byte{}
|
||||
greeting = append(greeting, []byte("hello ")...)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
By analogy with the similar property of <code>copy</code>, Go 1
|
||||
permits a string to be appended (byte-wise) directly to a byte
|
||||
slice; the conversion is no longer necessary:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/append.*world/`}}
|
||||
--> greeting = append(greeting, "world"...)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
This is a new feature, so existing code needs no changes.
|
||||
</p>
|
||||
|
||||
<h3 id="close">Close</h3>
|
||||
|
||||
<p>
|
||||
The <code>close</code> built-in function lets a sender tell a receiver
|
||||
that no more data will be transmitted on the channel. In Go 1 the
|
||||
type system enforces the directionality when possible: it is illegal
|
||||
to call <code>close</code> on a receive-only channel:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var c chan int
|
||||
var csend chan<- int = c
|
||||
var crecv <-chan int = c
|
||||
close(c) // legal
|
||||
close(csend) // legal
|
||||
close(crecv) // illegal
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
Existing code that attempts to close a receive-only channel was
|
||||
erroneous even before Go 1 and should be fixed. The compiler will
|
||||
now reject such code.
|
||||
</p>
|
||||
|
||||
<h3 id="literals">Composite literals</h3>
|
||||
|
||||
<h3 id="init">Goroutines during init</h3>
|
||||
|
||||
<p>
|
||||
Go 1 allows goroutines to be created and run during initialization.
|
||||
(They used to be created but were not run until after initialization
|
||||
completed.) Code that uses goroutines can now be called from
|
||||
<code>init</code> routines and global initialization expressions
|
||||
without introducing a deadlock.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/PackageGlobal/` `/^}/`}}
|
||||
-->var PackageGlobal int
|
||||
|
||||
func init() {
|
||||
c := make(chan int)
|
||||
go initializationFunction(c)
|
||||
PackageGlobal = <-c
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
This is a new feature, so existing code needs no changes,
|
||||
although it's possible that code that depends on goroutines not starting before <code>main</code> will break.
|
||||
There was no such code in the standard repository.
|
||||
</p>
|
||||
|
||||
<h3 id="rune">The rune type</h3>
|
||||
|
||||
<h3 id="delete">Deleting from maps</h3>
|
||||
@ -77,14 +152,161 @@ the ignored value can be safely discarded from the program and
|
||||
will flag other uses of the syntax for inspection by the programmer.
|
||||
</p>
|
||||
|
||||
<h3 id="map_iteration">Iterating in maps</h3>
|
||||
<h3 id="iteration">Iterating in maps</h3>
|
||||
|
||||
<p>
|
||||
In Go 1, the order in which elements are visited when iterating
|
||||
over a map using a <code>for</code> <code>range</code> statement
|
||||
is defined to be unpredictable, even if the same loop is run multiple
|
||||
times with the same map.
|
||||
Code should not assume that the elements are visited in any particular order.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/Sunday/` `/^ }/`}}
|
||||
--> m := map[string]int{"Sunday": 0, "Monday": 1}
|
||||
for name, value := range m {
|
||||
// This loop should not assume Sunday will be visited first.
|
||||
f(name, value)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
This is one change where tools cannot help. Most existing code
|
||||
will be unaffected, but some programs may break or misbehave; we
|
||||
recommend manual checking of all range statements over maps to
|
||||
verify they do not depend on iteration order. There were a few such
|
||||
examples in the standard repository; they have been fixed.
|
||||
Note that it was already incorrect to depend on the iteration order, which
|
||||
was unspecified. This change codifies the unpredictability.
|
||||
</p>
|
||||
|
||||
<h3 id="multiple_assignment">Multiple assignment</h3>
|
||||
|
||||
<p>
|
||||
Go 1 fully specifies the evaluation order in multiple assignment
|
||||
statements. In particular, if the left-hand side of the assignment
|
||||
statement contains expressions that require evaluation, such as
|
||||
function calls or array indexing operations, these will all be done
|
||||
using the usual left-to-right rule before any variables are assigned
|
||||
their value. Once everything is evaluated, the actual assignments
|
||||
proceed in left-to-right order.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
These examples illustrate the behavior.
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/sa :=/` `/then sc.0. = 2/`}}
|
||||
--> sa := []int{1, 2, 3}
|
||||
i := 0
|
||||
i, sa[i] = 1, 2 // sets i = 1, sa[0] = 2
|
||||
|
||||
sb := []int{1, 2, 3}
|
||||
j := 0
|
||||
sb[j], j = 2, 1 // sets sb[0] = 2, j = 1
|
||||
|
||||
sc := []int{1, 2, 3}
|
||||
sc[0], sc[0] = 1, 2 // sets sc[0] = 1, then sc[0] = 2 (so sc[0] = 2 at end)
|
||||
</pre>
|
||||
|
||||
<em>Updating</em>:
|
||||
This is one change where tools cannot help, but breakage is unlikely.
|
||||
No code in the standard repository was broken by this change, and code
|
||||
that depended on the previous unspecified behavior was already incorrect.
|
||||
</p>
|
||||
|
||||
<h3 id="shadowing">Returns and shadowed variables</h3>
|
||||
|
||||
<p>
|
||||
A shadowed variable is one that has the same name as another variable in an inner scope.
|
||||
In functions with named return values,
|
||||
the Go 1 compilers disallow return statements without arguments if any of the named return values is shadowed at the point of the return statement.
|
||||
(It isn't part of the specification, because this is one area we are still exploring;
|
||||
the situation is analogous to the compilers rejecting functions that do not end with an explicit return statement.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This function implicitly returns a shadowed return value and will be rejected by the compiler:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func Bug() (i, j, k int) {
|
||||
for i = 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ { // Redeclares j.
|
||||
k += i*j
|
||||
if k > 100 {
|
||||
return // Rejected: j is shadowed here.
|
||||
}
|
||||
}
|
||||
}
|
||||
return // OK: j is not shadowed here.
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
Code that shadows return values in this way will be rejected by the compiler and will need to be fixed by hand.
|
||||
The few cases that arose in the standard repository were mostly bugs.
|
||||
</p>
|
||||
|
||||
<h3 id="unexported">Copying structs with unexported fields</h3>
|
||||
|
||||
<h3 id="equality">Equality of structs and arrays</h3>
|
||||
|
||||
<p>
|
||||
Go 1 defines equality and inequality (<code>==</code> and
|
||||
<code>!=</code>) for struct and array values, respectively, provided
|
||||
the elements of the data structures can themselves be compared.
|
||||
That is, if equality is defined for all the fields of a struct (or
|
||||
an array element), then it is defined for the struct (or array).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As a result, structs and arrays can now be used as map keys:
|
||||
</p>
|
||||
|
||||
<pre><!--{{code "progs/go1.go" `/type Day struct/` `/Printf/`}}
|
||||
--> // type Day struct {
|
||||
// long string
|
||||
// short string
|
||||
// }
|
||||
// Christmas := Day{"Christmas", "XMas"}
|
||||
// Thanksgiving := Day{"Thanksgiving", "Turkey"}
|
||||
// holiday := map[Day]bool {
|
||||
// Christmas: true,
|
||||
// Thanksgiving: true,
|
||||
// }
|
||||
// fmt.Printf("Christmas is a holiday: %t\n", holiday[Christmas])
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Note that equality is still undefined for slices, for which the
|
||||
calculation is in general infeasible. Also note that the ordered
|
||||
comparison operators (<code><</code> <code><=</code>
|
||||
<code>></code> <code>>=</code>) are still undefined for
|
||||
structs and arrays.
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
This is a new feature, so existing code needs no changes.
|
||||
</p>
|
||||
|
||||
<h3 id="funcs">Function and map equality</h3>
|
||||
|
||||
<p>
|
||||
Go 1 disallows checking for equality of functions and maps,
|
||||
respectively, except to compare them directly to <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
Existing code that depends on function or map equality will be
|
||||
rejected by the compiler and will need to be fixed by hand.
|
||||
Few programs will be affected, but the fix may require some
|
||||
redesign.
|
||||
</p>
|
||||
|
||||
<h2 id="library">Changes to the library</h2>
|
||||
|
||||
<h3 id="hierarchy">The package hierarchy</h3>
|
||||
@ -106,7 +328,7 @@ while <a href="#deleted">others</a> have been deleted outright.
|
||||
<th align="left">Old path</th>
|
||||
<th align="left">New path</th>
|
||||
</tr>
|
||||
<tr><td>asn1 <td>encoding/asn1
|
||||
<tr><td>asn1</td> <td>encoding/asn1</td></tr>
|
||||
<tr><td>csv</td> <td>encoding/csv</td></tr>
|
||||
<tr><td>gob</td> <td>encoding/gob</td></tr>
|
||||
<tr><td>json</td> <td>encoding/json</td></tr>
|
||||
|
182
doc/go1.tmpl
182
doc/go1.tmpl
@ -27,17 +27,79 @@ r60 to compile and run under Go 1. Finally, it outlines the new
|
||||
<code>go</code> command for building Go programs and the new binary
|
||||
release process being introduced. Most of these topics have more
|
||||
thorough presentations elsewhere; such documents are linked below.
|
||||
</p>
|
||||
|
||||
<h2 id="language">Changes to the language</h2>
|
||||
|
||||
<h3 id="append">Append</h3>
|
||||
|
||||
<p>
|
||||
The <code>append</code> built-in function is variadic, so one can
|
||||
append to a byte slice using the <code>...</code> syntax in the
|
||||
call.
|
||||
</p>
|
||||
|
||||
{{code "progs/go1.go" `/greeting := ..byte/` `/append.*hello/`}}
|
||||
|
||||
<p>
|
||||
By analogy with the similar property of <code>copy</code>, Go 1
|
||||
permits a string to be appended (byte-wise) directly to a byte
|
||||
slice; the conversion is no longer necessary:
|
||||
</p>
|
||||
|
||||
{{code "progs/go1.go" `/append.*world/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
This is a new feature, so existing code needs no changes.
|
||||
</p>
|
||||
|
||||
<h3 id="close">Close</h3>
|
||||
|
||||
<p>
|
||||
The <code>close</code> built-in function lets a sender tell a receiver
|
||||
that no more data will be transmitted on the channel. In Go 1 the
|
||||
type system enforces the directionality when possible: it is illegal
|
||||
to call <code>close</code> on a receive-only channel:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var c chan int
|
||||
var csend chan<- int = c
|
||||
var crecv <-chan int = c
|
||||
close(c) // legal
|
||||
close(csend) // legal
|
||||
close(crecv) // illegal
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
Existing code that attempts to close a receive-only channel was
|
||||
erroneous even before Go 1 and should be fixed. The compiler will
|
||||
now reject such code.
|
||||
</p>
|
||||
|
||||
<h3 id="literals">Composite literals</h3>
|
||||
|
||||
<h3 id="init">Goroutines during init</h3>
|
||||
|
||||
<p>
|
||||
Go 1 allows goroutines to be created and run during initialization.
|
||||
(They used to be created but were not run until after initialization
|
||||
completed.) Code that uses goroutines can now be called from
|
||||
<code>init</code> routines and global initialization expressions
|
||||
without introducing a deadlock.
|
||||
</p>
|
||||
|
||||
{{code "progs/go1.go" `/PackageGlobal/` `/^}/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
This is a new feature, so existing code needs no changes,
|
||||
although it's possible that code that depends on goroutines not starting before <code>main</code> will break.
|
||||
There was no such code in the standard repository.
|
||||
</p>
|
||||
|
||||
<h3 id="rune">The rune type</h3>
|
||||
|
||||
<h3 id="delete">Deleting from maps</h3>
|
||||
@ -71,14 +133,132 @@ the ignored value can be safely discarded from the program and
|
||||
will flag other uses of the syntax for inspection by the programmer.
|
||||
</p>
|
||||
|
||||
<h3 id="map_iteration">Iterating in maps</h3>
|
||||
<h3 id="iteration">Iterating in maps</h3>
|
||||
|
||||
<p>
|
||||
In Go 1, the order in which elements are visited when iterating
|
||||
over a map using a <code>for</code> <code>range</code> statement
|
||||
is defined to be unpredictable, even if the same loop is run multiple
|
||||
times with the same map.
|
||||
Code should not assume that the elements are visited in any particular order.
|
||||
</p>
|
||||
|
||||
{{code "progs/go1.go" `/Sunday/` `/^ }/`}}
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
This is one change where tools cannot help. Most existing code
|
||||
will be unaffected, but some programs may break or misbehave; we
|
||||
recommend manual checking of all range statements over maps to
|
||||
verify they do not depend on iteration order. There were a few such
|
||||
examples in the standard repository; they have been fixed.
|
||||
Note that it was already incorrect to depend on the iteration order, which
|
||||
was unspecified. This change codifies the unpredictability.
|
||||
</p>
|
||||
|
||||
<h3 id="multiple_assignment">Multiple assignment</h3>
|
||||
|
||||
<p>
|
||||
Go 1 fully specifies the evaluation order in multiple assignment
|
||||
statements. In particular, if the left-hand side of the assignment
|
||||
statement contains expressions that require evaluation, such as
|
||||
function calls or array indexing operations, these will all be done
|
||||
using the usual left-to-right rule before any variables are assigned
|
||||
their value. Once everything is evaluated, the actual assignments
|
||||
proceed in left-to-right order.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
These examples illustrate the behavior.
|
||||
</p>
|
||||
|
||||
{{code "progs/go1.go" `/sa :=/` `/then sc.0. = 2/`}}
|
||||
|
||||
<em>Updating</em>:
|
||||
This is one change where tools cannot help, but breakage is unlikely.
|
||||
No code in the standard repository was broken by this change, and code
|
||||
that depended on the previous unspecified behavior was already incorrect.
|
||||
</p>
|
||||
|
||||
<h3 id="shadowing">Returns and shadowed variables</h3>
|
||||
|
||||
<p>
|
||||
A shadowed variable is one that has the same name as another variable in an inner scope.
|
||||
In functions with named return values,
|
||||
the Go 1 compilers disallow return statements without arguments if any of the named return values is shadowed at the point of the return statement.
|
||||
(It isn't part of the specification, because this is one area we are still exploring;
|
||||
the situation is analogous to the compilers rejecting functions that do not end with an explicit return statement.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This function implicitly returns a shadowed return value and will be rejected by the compiler:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func Bug() (i, j, k int) {
|
||||
for i = 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ { // Redeclares j.
|
||||
k += i*j
|
||||
if k > 100 {
|
||||
return // Rejected: j is shadowed here.
|
||||
}
|
||||
}
|
||||
}
|
||||
return // OK: j is not shadowed here.
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
Code that shadows return values in this way will be rejected by the compiler and will need to be fixed by hand.
|
||||
The few cases that arose in the standard repository were mostly bugs.
|
||||
</p>
|
||||
|
||||
<h3 id="unexported">Copying structs with unexported fields</h3>
|
||||
|
||||
<h3 id="equality">Equality of structs and arrays</h3>
|
||||
|
||||
<p>
|
||||
Go 1 defines equality and inequality (<code>==</code> and
|
||||
<code>!=</code>) for struct and array values, respectively, provided
|
||||
the elements of the data structures can themselves be compared.
|
||||
That is, if equality is defined for all the fields of a struct (or
|
||||
an array element), then it is defined for the struct (or array).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
As a result, structs and arrays can now be used as map keys:
|
||||
</p>
|
||||
|
||||
{{code "progs/go1.go" `/type Day struct/` `/Printf/`}}
|
||||
|
||||
<p>
|
||||
Note that equality is still undefined for slices, for which the
|
||||
calculation is in general infeasible. Also note that the ordered
|
||||
comparison operators (<code><</code> <code><=</code>
|
||||
<code>></code> <code>>=</code>) are still undefined for
|
||||
structs and arrays.
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
This is a new feature, so existing code needs no changes.
|
||||
</p>
|
||||
|
||||
<h3 id="funcs">Function and map equality</h3>
|
||||
|
||||
<p>
|
||||
Go 1 disallows checking for equality of functions and maps,
|
||||
respectively, except to compare them directly to <code>nil</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<em>Updating</em>:
|
||||
Existing code that depends on function or map equality will be
|
||||
rejected by the compiler and will need to be fixed by hand.
|
||||
Few programs will be affected, but the fix may require some
|
||||
redesign.
|
||||
</p>
|
||||
|
||||
<h2 id="library">Changes to the library</h2>
|
||||
|
||||
<h3 id="hierarchy">The package hierarchy</h3>
|
||||
|
@ -9,7 +9,11 @@ package main
|
||||
import "log"
|
||||
|
||||
func main() {
|
||||
stringAppend()
|
||||
mapDelete()
|
||||
mapIteration()
|
||||
multipleAssignment()
|
||||
structEquality()
|
||||
}
|
||||
|
||||
func mapDelete() {
|
||||
@ -20,3 +24,73 @@ func mapDelete() {
|
||||
log.Fatal("mapDelete:", m)
|
||||
}
|
||||
}
|
||||
|
||||
func stringAppend() {
|
||||
greeting := []byte{}
|
||||
greeting = append(greeting, []byte("hello ")...)
|
||||
greeting = append(greeting, "world"...)
|
||||
if string(greeting) != "hello world" {
|
||||
log.Fatal("stringAppend: ", string(greeting))
|
||||
}
|
||||
}
|
||||
|
||||
func mapIteration() {
|
||||
m := map[string]int{"Sunday": 0, "Monday": 1}
|
||||
for name, value := range m {
|
||||
// This loop should not assume Sunday will be visited first.
|
||||
f(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
func assert(t bool) {
|
||||
if !t {
|
||||
log.Panic("assertion fail")
|
||||
}
|
||||
}
|
||||
|
||||
func multipleAssignment() {
|
||||
sa := []int{1, 2, 3}
|
||||
i := 0
|
||||
i, sa[i] = 1, 2 // sets i = 1, sa[0] = 2
|
||||
|
||||
sb := []int{1, 2, 3}
|
||||
j := 0
|
||||
sb[j], j = 2, 1 // sets sb[0] = 2, j = 1
|
||||
|
||||
sc := []int{1, 2, 3}
|
||||
sc[0], sc[0] = 1, 2 // sets sc[0] = 1, then sc[0] = 2 (so sc[0] = 2 at end)
|
||||
|
||||
assert(i == 1 && sa[0] == 2)
|
||||
assert(j == 1 && sb[0] == 2)
|
||||
assert(sc[0] == 2)
|
||||
}
|
||||
|
||||
func structEquality() {
|
||||
// Feature not net in repo.
|
||||
// type Day struct {
|
||||
// long string
|
||||
// short string
|
||||
// }
|
||||
// Christmas := Day{"Christmas", "XMas"}
|
||||
// Thanksgiving := Day{"Thanksgiving", "Turkey"}
|
||||
// holiday := map[Day]bool {
|
||||
// Christmas: true,
|
||||
// Thanksgiving: true,
|
||||
// }
|
||||
// fmt.Printf("Christmas is a holiday: %t\n", holiday[Christmas])
|
||||
}
|
||||
|
||||
func f(string, int) {
|
||||
}
|
||||
|
||||
func initializationFunction(c chan int) {
|
||||
c <- 1
|
||||
}
|
||||
|
||||
var PackageGlobal int
|
||||
|
||||
func init() {
|
||||
c := make(chan int)
|
||||
go initializationFunction(c)
|
||||
PackageGlobal = <-c
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user