1
0
mirror of https://github.com/golang/go synced 2024-11-23 20:20:01 -07:00

go for c++ programmers; fixes.

the most substantial are the wording around semicolons
and around the channel manager nits.  both were subtly
incorrect.

R=iant, r
CC=go-dev
http://go/go-review/1025018
This commit is contained in:
Russ Cox 2009-11-08 01:08:26 -08:00
parent 24ce19c71d
commit 2a63f5df98

View File

@ -1,7 +1,8 @@
<!-- Go For C++ Programmers -->
<p>
Go is a systems programming language intended as an alternative to C++.
Go is a systems programming language intended to be a general-purpose
systems language, like C++.
These are some notes on Go for experienced C++ programmers. This
document discusses the differences between Go and C++, and says little
to nothing about the similarities.
@ -15,9 +16,6 @@ For a more general introduction to Go, see the
For a detailed description of the Go language, see the
<a href="go_spec.html">Go spec</a>.
<p>
There is more <a href="/">documentation about go</a>.
<h2 id="Conceptual_Differences">Conceptual Differences</h2>
<ul>
@ -27,11 +25,11 @@ There is more <a href="/">documentation about go</a>.
<a href="#Interfaces">discussed in more detail below</a>.
Interfaces are also used where C++ uses templates.
<li>Go uses garbage collection. It is not necessary (or currently possible)
to explicitly release memory. The garbage collection is (intended to be)
<li>Go uses garbage collection. It is not necessary (or possible)
to release memory explicitly. The garbage collection is (intended to be)
incremental and highly efficient on modern processors.
<li>Go supports pointers, but does not support pointer arithmetic. You cannot
<li>Go has pointers but not pointer arithmetic. You cannot
use a pointer variable to walk through the bytes of a string.
<li>Arrays in Go are first class values. When an array is used as a
@ -77,19 +75,19 @@ There is more <a href="/">documentation about go</a>.
<p>
The declaration syntax is reversed compared to C++. You write the name
followed by the type. Unlike C++, the syntax for a type does not match
followed by the type. Unlike in C++, the syntax for a type does not match
the way in which the variable is used. Type declarations may be read
easily from left to right.
<pre>
<b>Go C++</b>
var v1 int; // int v1;
var v2 string; // approximately const std::string v2;
var v2 string; // const std::string v2; (approximately)
var v3 [10]int; // int v3[10];
var v4 []int; // approximately int* v4;
var v4 []int; // int* v4; (approximately)
var v5 struct { f int }; // struct { int f; } v5;
var v6 *int; // int* v6; // but no pointer arithmetic
var v7 map[string]int; // approximately unordered_map&lt;string, int&gt;* v7;
var v6 *int; // int* v6; (but no pointer arithmetic)
var v7 map[string]int; // unordered_map&lt;string, int&gt;* v7; (approximately)
var v8 func(a int) int; // int (*v8)(int a);
</pre>
@ -99,7 +97,7 @@ of the object being declared. The keyword is one of <code>var</code>,
<code>func</code>,
<code>const</code>, or <code>type</code>. Method declarations are a minor
exception in that
the receiver appears before the name of the object begin declared; see
the receiver appears before the name of the object being declared; see
the <a href="#Interfaces">discussion of interfaces</a>.
<p>
@ -107,7 +105,10 @@ You can also use a keyword followed by a series of declarations in
parentheses.
<pre>
var (i int; m float)
var (
i int;
m float
)
</pre>
<p>
@ -116,7 +117,7 @@ or not provide a name for any parameter; you can't omit some names
and provide others. You may group several names with the same type:
<pre>
func f (i, j, k int);
func f(i, j, k int, s, t string);
</pre>
<p>
@ -131,13 +132,13 @@ var v = *p;
<p>
See also the <a href="#Constants">discussion of constants, below</a>.
If a variable is not initialized, the type must be specified.
If a variable is not initialized explicitly, the type must be specified.
In that case it will be
implicitly initialized to 0 (or nil, or whatever). There are no
implicitly initialized to the type's zero value (0, nil, etc.). There are no
uninitialized variables in Go.
<p>
Within a function, a simple declaration syntax is available with
Within a function, a short declaration syntax is available with
<code>:=</code> .
<pre>
@ -170,9 +171,10 @@ v1, v2 = f();
<p>
Go treats semicolons as separators, not terminators. Moreover,
a semicolon
is not required after a curly brace ending a type declaration (e.g.,
<code>var s struct {}</code>) or a block. Semicolons are never required at the
semicolons may be omitted after the closing parenthesis of a declaration
block or after a closing brace that is not part of an expression
(e.g., <code>var s struct {}</code> or <code>{ x++ }</code>).
Semicolons are never required at the
top level of a file (between global declarations). However, they are
always <em>permitted</em> at
the end of a statement, so you can continue using them as in C++.
@ -198,7 +200,7 @@ around the body of an <code>if</code> or <code>for</code> statement.
<pre>
if a &lt; b { f() } // Valid
if (a &lt; b) { f() } // Valid (condition is parenthesized expression)
if (a &lt; b) { f() } // Valid (condition is a parenthesized expression)
if (a &lt; b) f(); // INVALID
for i = 0; i < 10; i++ {} // Valid
for (i = 0; i < 10; i++) {} // INVALID
@ -224,14 +226,21 @@ make them fall through using the <code>fallthrough</code> keyword. This applies
even to adjacent cases.
<pre>
switch i { case 0: case 1: f() } // f is not called when i == 0!
switch i {
case 0: // empty case body
case 1:
f() // f is not called when i == 0!
}
</pre>
<p>
But a <code>case</code> can have multiple values.
<pre>
switch i { case 0, 1: f() } // f is called if i == 0 || i == 1.
switch i {
case 0, 1:
f() // f is called if i == 0 || i == 1.
}
</pre>
<p>
@ -242,7 +251,14 @@ pointers, can be used&mdash;and if the <code>switch</code>
value is omitted it defaults to <code>true</code>.
<pre>
switch { case i &lt; 0: f1() case i == 0: f2() case i &gt; 0: f3() }
switch {
case i &lt; 0:
f1()
case i == 0:
f2()
case i &gt; 0:
f3()
}
</pre>
<p>
@ -264,7 +280,7 @@ defer close(fd); // fd will be closed when this function returns.
<p>
In Go constants may be <i>untyped</i>. This applies even to constants
named with a <code>const</code> declaration if no
named with a <code>const</code> declaration, if no
type is given in the declaration and the initializer expression uses only
untyped constants.
A value derived from an untyped constant becomes typed when it
@ -273,7 +289,8 @@ requires a typed value. This permits constants to be used relatively
freely without requiring general implicit type conversion.
<pre>
var a uint; f(a + 1) // untyped numeric constant "1" becomes typed as uint
var a uint;
f(a + 1) // untyped numeric constant "1" becomes typed as uint
</pre>
<p>
@ -282,7 +299,8 @@ numeric constant or constant expression. A limit is only applied when
a constant is used where a type is required.
<pre>
const huge = 1 &lt;&lt; 100; f(huge &gt;&gt; 98)
const huge = 1 &lt;&lt; 100;
f(huge &gt;&gt; 98)
</pre>
<p>
@ -293,7 +311,11 @@ value. When an initialization expression is omitted for a <code>const</code>,
it reuses the preceding expression.
<pre>
const ( red = iota; blue; green ) // red == 0, blue == 1, green == 2
const (
red = iota; // red == 0
blue; // blue == 1
green // green == 2
)
</pre>
<h2 id="Slices">Slices</h2>
@ -312,19 +334,18 @@ capacity.
Given an array, or another slice, a new slice is created via
<code>a[I:J]</code>. This
creates a new slice which refers to <code>a</code>, starts at
index <code>I</code>, and ends at index
<code>J - 1</code>. It has length <code>J - I</code>.
index <code>I</code>, and ends before index
<code>J</code>. It has length <code>J - I</code>.
The new slice refers to the same array
to which <code>a</code>
refers. That is, changes made using the new slice may be seen using
<code>a</code>. The
capacity of the new slice is simply the capacity of <code>a</code> minus
<code>I</code>. The capacity
of an array is the length of the array. You may also assign a pointer to an
array to a
variable of slice type; given <code>var s []int; var a[10] int</code>,
<code>s = &amp;a</code> is more or
less the same as <code>s = a[0:len(a)]</code>.
of an array is the length of the array. You may also assign an array pointer
to a variable of slice type; given <code>var s []int; var a[10] int</code>,
the assignment <code>s = &amp;a</code> is equivalent to
<code>s = a[0:len(a)]</code>.
<p>
What this means is that Go uses slices for some cases where C++ uses pointers.
@ -333,7 +354,7 @@ perhaps a
buffer) and you want to pass it to a function without copying it, you should
declare the function parameter to have type <code>[]byte</code>, and pass the
address
of the array. Unlike C++, it is not
of the array. Unlike in C++, it is not
necessary to pass the length of the buffer; it is efficiently accessible via
<code>len</code>.
@ -437,7 +458,7 @@ type myInterface interface {
</pre>
<p>
we can make <code>myType</code> satisfy the interface by additionally writing
we can make <code>myType</code> satisfy the interface by adding
<pre>
func (p *myType) set(i int) { p.i = i }
@ -469,7 +490,7 @@ class.
<pre>
type myChildType struct { myType; j int }
func (p *myChildType) get() int { p.j++; return (&amp;p.myType).get() }
func (p *myChildType) get() int { p.j++; return p.myType.get() }
</pre>
<p>
@ -486,7 +507,7 @@ func f2() {
<p>
The <code>set</code> method is effectively inherited from
<code>myChildType</code>, because
methods associated with the anonymous type are promoted to become methods
methods associated with the anonymous field are promoted to become methods
of the enclosing type. In this case, because <code>myChildType</code> has an
anonymous field of type <code>myType</code>, the methods of
<code>myType</code> also become methods of <code>myChildType</code>.
@ -494,12 +515,11 @@ In this example, the <code>get</code> method was
overridden, and the <code>set</code> method was inherited.
<p>
This is not precisely the same as a child class in C++. When a parent
method is called, it receives a pointer to the field in the child class.
If the parent method calls some other method on its argument, it will call
the method associated with the parent class, not the method associated with
the child class. In other words, methods are not virtual functions. When
you want the equivalent of a virtual function, use an interface.
This is not precisely the same as a child class in C++.
When a method of an anonymous field is called,
its receiver is the field, not the surrounding struct.
In other words, methods on anonymous fields are not virtual functions.
When you want the equivalent of a virtual function, use an interface.
<p>
A variable which has an interface type may be converted to have a
@ -565,8 +585,14 @@ multiple operating system threads. You do not have to worry
about these details.
<pre>
func server(i int) { for { print(i); sys.sleep(10) } }
go server(1); go server(2);
func server(i int) {
for {
print(i);
sys.sleep(10)
}
}
go server(1);
go server(2);
</pre>
<p>
@ -586,7 +612,7 @@ go func(i int) {
s := 0
for j := 0; j &lt; i; j++ { s += j }
g = s;
} (1000); // Passes argument 1000 to the function literal.
}(1000); // Passes argument 1000 to the function literal.
</pre>
<h2 id="Channels">Channels</h2>
@ -619,11 +645,12 @@ func manager(ch chan cmd) {
</pre>
<p>
In that example the same channel is used for input and output. This
means that if two goroutines try to retrieve the value at the same
time, the first goroutine may read the response which was triggered by
the second goroutine's request. In simple cases that is fine. For more
complex cases, pass in a channel.
In that example the same channel is used for input and output.
This is incorrect if there are multiple goroutines communicating
with the manager at once: a goroutine waiting for a response
from the manager might receive a request from another goroutine
instead.
A solution is to pass in a channel.
<pre>
type cmd2 struct { get bool; val int; ch &lt;- chan int; }
@ -645,6 +672,6 @@ func f4(ch &lt;- chan cmd2) int {
myCh := make(chan int);
c := cmd2{ true, 0, myCh }; // Composite literal syntax.
ch &lt;- c;
return &lt;- myCh;
return &lt;-myCh;
}
</pre>