1
0
mirror of https://github.com/golang/go synced 2024-11-21 22:34:48 -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:
Rob Pike 2011-12-08 16:39:05 -08:00
parent 27cab90363
commit 136c04f71a
3 changed files with 479 additions and 3 deletions

View File

@ -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(&#34;hello &#34;)...)
</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, &#34;world&#34;...)
</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 = &lt;-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{&#34;Sunday&#34;: 0, &#34;Monday&#34;: 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{&#34;Christmas&#34;, &#34;XMas&#34;}
// Thanksgiving := Day{&#34;Thanksgiving&#34;, &#34;Turkey&#34;}
// holiday := map[Day]bool {
// Christmas: true,
// Thanksgiving: true,
// }
// fmt.Printf(&#34;Christmas is a holiday: %t\n&#34;, 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>&lt;</code> <code>&lt;=</code>
<code>&gt;</code> <code>&gt;=</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>

View File

@ -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>&lt;</code> <code>&lt;=</code>
<code>&gt;</code> <code>&gt;=</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>

View File

@ -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
}