зеркало из https://github.com/CryptoPro/go.git
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:
Родитель
24ce19c71d
Коммит
2a63f5df98
|
@ -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<string, int>* v7;
|
||||
var v6 *int; // int* v6; (but no pointer arithmetic)
|
||||
var v7 map[string]int; // unordered_map<string, int>* 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 < b { f() } // Valid
|
||||
if (a < b) { f() } // Valid (condition is parenthesized expression)
|
||||
if (a < b) { f() } // Valid (condition is a parenthesized expression)
|
||||
if (a < 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—and if the <code>switch</code>
|
|||
value is omitted it defaults to <code>true</code>.
|
||||
|
||||
<pre>
|
||||
switch { case i < 0: f1() case i == 0: f2() case i > 0: f3() }
|
||||
switch {
|
||||
case i < 0:
|
||||
f1()
|
||||
case i == 0:
|
||||
f2()
|
||||
case i > 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 << 100; f(huge >> 98)
|
||||
const huge = 1 << 100;
|
||||
f(huge >> 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 = &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 = &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 (&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 < 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 <- chan int; }
|
||||
|
@ -645,6 +672,6 @@ func f4(ch <- chan cmd2) int {
|
|||
myCh := make(chan int);
|
||||
c := cmd2{ true, 0, myCh }; // Composite literal syntax.
|
||||
ch <- c;
|
||||
return <- myCh;
|
||||
return <-myCh;
|
||||
}
|
||||
</pre>
|
||||
|
|
Загрузка…
Ссылка в новой задаче