mirror of
https://github.com/golang/go
synced 2024-11-21 22:54:40 -07:00
doc: remove Go for C++ Programmers
Now available at the Go Wiki: http://code.google.com/p/go-wiki/wiki/GoForCPPProgrammers Fixes #2913. R=golang-dev, r CC=golang-dev https://golang.org/cl/5705049
This commit is contained in:
parent
2c9e1637d2
commit
5fea39d0b4
@ -60,7 +60,6 @@ Answers to common questions about Go.
|
||||
<ul>
|
||||
<li><a href="/doc/articles/wiki/">Writing Web Applications</a> -
|
||||
building a simple web application.</li>
|
||||
<li><a href="go_for_cpp_programmers.html">Go for C++ Programmers</a></li>
|
||||
</ul>
|
||||
|
||||
<h2 id="articles">Go Articles</h2>
|
||||
|
@ -1,807 +0,0 @@
|
||||
<!--{
|
||||
"Title": "Go For C++ Programmers"
|
||||
}-->
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For a more general introduction to Go, see the
|
||||
<a href="http://tour.golang.org/">Go Tour</a>,
|
||||
<a href="/doc/code.html">How to Write Go Code</a>
|
||||
and <a href="effective_go.html">Effective Go</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For a detailed description of the Go language, see the
|
||||
<a href="go_spec.html">Go spec</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="Conceptual_Differences">Conceptual Differences</h2>
|
||||
|
||||
<ul>
|
||||
<li>Go does not have classes with constructors or destructors.
|
||||
Instead of class methods, a class inheritance hierarchy,
|
||||
and virtual functions, Go provides <em>interfaces</em>, which are
|
||||
<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 possible)
|
||||
to release memory explicitly.
|
||||
|
||||
<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
|
||||
function parameter, the function receives a copy of the array, not
|
||||
a pointer to it. However, in practice functions often use slices
|
||||
for parameters; slices hold pointers to underlying arrays. Slices
|
||||
are <a href="#Slices">discussed further below</a>.
|
||||
|
||||
<li>Strings are provided by the language. They may not be changed once they
|
||||
have been created.
|
||||
|
||||
<li>Hash tables are provided by the language. They are called maps.
|
||||
|
||||
<li>Separate threads of execution, and communication channels between
|
||||
them, are provided by the language. This
|
||||
is <a href="#Goroutines">discussed further below</a>.
|
||||
|
||||
<li>Certain types (maps and channels, described further below)
|
||||
are passed by reference, not by value. That is, passing a map to a
|
||||
function does not copy the map, and if the function changes the map
|
||||
the change will be seen by the caller. In C++ terms, one can
|
||||
think of these as being reference types.
|
||||
|
||||
<li>Go does not use header files. Instead, each source file is part of a
|
||||
defined <em>package</em>. When a package defines an object
|
||||
(type, constant, variable, function) with a name starting with an
|
||||
upper case letter, that object is visible to any other file which
|
||||
imports that package.
|
||||
|
||||
<li>Go does not support implicit type conversion. Operations that mix
|
||||
different types require casts (called conversions in Go).
|
||||
|
||||
<li>Go does not support function overloading and does not support user
|
||||
defined operators.
|
||||
|
||||
<li>Go does not support <code>const</code> or <code>volatile</code> qualifiers.
|
||||
|
||||
<li>Go uses <code>nil</code> for invalid pointers, where C++ uses
|
||||
<code>NULL</code> or simply <code>0</code>.
|
||||
</ul>
|
||||
|
||||
<h2 id="Syntax">Syntax</h2>
|
||||
|
||||
<p>
|
||||
The declaration syntax is reversed compared to C++. You write the name
|
||||
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.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
<b>Go C++</b>
|
||||
var v1 int // int v1;
|
||||
var v2 string // const std::string v2; (approximately)
|
||||
var v3 [10]int // int v3[10];
|
||||
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 // unordered_map<string, int>* v7; (approximately)
|
||||
var v8 func(a int) int // int (*v8)(int a);
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Declarations generally take the form of a keyword followed by the name
|
||||
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 being declared; see
|
||||
the <a href="#Interfaces">discussion of interfaces</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can also use a keyword followed by a series of declarations in
|
||||
parentheses.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var (
|
||||
i int
|
||||
m float64
|
||||
)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
When declaring a function, you must either provide a name for each parameter
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func f(i, j, k int, s, t string)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
A variable may be initialized when it is declared. When this is done,
|
||||
specifying the type is permitted but not required. When the type is
|
||||
not specified, the type of the variable is the type of the
|
||||
initialization expression.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var v = *p
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
See also the <a href="#Constants">discussion of constants, below</a>.
|
||||
If a variable is not initialized explicitly, the type must be specified.
|
||||
In that case it will be
|
||||
implicitly initialized to the type's zero value
|
||||
(<code>0</code>, <code>nil</code>, etc.). There are no
|
||||
uninitialized variables in Go.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Within a function, a short declaration syntax is available with
|
||||
<code>:=</code> .
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
v1 := v2
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This is equivalent to
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var v1 = v2
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Go permits multiple assignments, which are done in parallel.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
i, j = j, i // Swap i and j.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Functions may have multiple return values, indicated by a list in
|
||||
parentheses. The returned values can be stored by assignment
|
||||
to a list of variables.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func f() (i int, j int) { ... }
|
||||
v1, v2 = f()
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Go code uses very few semicolons in practice. Technically, all Go
|
||||
statements are terminated by a semicolon. However, Go treats the end
|
||||
of a non-blank line as a semicolon unless the line is clearly
|
||||
incomplete (the exact rules are
|
||||
in <a href="go_spec.html#Semicolons">the language specification</a>).
|
||||
A consequence of this is that in some cases Go does not permit you to
|
||||
use a line break. For example, you may not write
|
||||
</p>
|
||||
<pre>
|
||||
func g()
|
||||
{ // INVALID
|
||||
}
|
||||
</pre>
|
||||
<p>
|
||||
A semicolon will be inserted after <code>g()</code>, causing it to be
|
||||
a function declaration rather than a function definition. Similarly,
|
||||
you may not write
|
||||
</p>
|
||||
<pre>
|
||||
if x {
|
||||
}
|
||||
else { // INVALID
|
||||
}
|
||||
</pre>
|
||||
<p>
|
||||
A semicolon will be inserted after the <code>}</code> preceding
|
||||
the <code>else</code>, causing a syntax error.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Since semicolons do end statements, you may continue using them as in
|
||||
C++. However, that is not the recommended style. Idiomatic Go code
|
||||
omits unnecessary semicolons, which in practice is all of them other
|
||||
than the initial <code>for</code> loop clause and cases where you want several
|
||||
short statements on a single line.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
While we're on the topic, we recommend that rather than worry about
|
||||
semicolons and brace placement, you format your code with
|
||||
the <code>gofmt</code> program. That will produce a single standard
|
||||
Go style, and let you worry about your code rather than your
|
||||
formatting. While the style may initially seem odd, it is as good as
|
||||
any other style, and familiarity will lead to comfort.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
When using a pointer to a struct, you use <code>.</code> instead
|
||||
of <code>-></code>.
|
||||
Thus syntactically speaking a structure and a pointer to a structure
|
||||
are used in the same way.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type myStruct struct { i int }
|
||||
var v9 myStruct // v9 has structure type
|
||||
var p9 *myStruct // p9 is a pointer to a structure
|
||||
f(v9.i, p9.i)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Go does not require parentheses around the condition of an <code>if</code>
|
||||
statement, or the expressions of a <code>for</code> statement, or the value of a
|
||||
<code>switch</code> statement. On the other hand, it does require curly braces
|
||||
around the body of an <code>if</code> or <code>for</code> statement.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
if a < b { f() } // Valid
|
||||
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
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Go does not have a <code>while</code> statement nor does it have a
|
||||
<code>do/while</code>
|
||||
statement. The <code>for</code> statement may be used with a single condition,
|
||||
which makes it equivalent to a <code>while</code> statement. Omitting the
|
||||
condition entirely is an endless loop.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Go permits <code>break</code> and <code>continue</code> to specify a label.
|
||||
The label must
|
||||
refer to a <code>for</code>, <code>switch</code>, or <code>select</code>
|
||||
statement.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In a <code>switch</code> statement, <code>case</code> labels do not fall
|
||||
through. You can
|
||||
make them fall through using the <code>fallthrough</code> keyword. This applies
|
||||
even to adjacent cases.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
switch i {
|
||||
case 0, 1:
|
||||
f() // f is called if i == 0 || i == 1.
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The values in a <code>case</code> need not be constants—or even integers;
|
||||
any type
|
||||
that supports the equality comparison operator, such as strings or
|
||||
pointers, can be used—and if the <code>switch</code>
|
||||
value is omitted it defaults to <code>true</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
switch {
|
||||
case i < 0:
|
||||
f1()
|
||||
case i == 0:
|
||||
f2()
|
||||
case i > 0:
|
||||
f3()
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>++</code> and <code>--</code> operators may only be used in
|
||||
statements, not in expressions.
|
||||
You cannot write <code>c = *p++</code>. <code>*p++</code> is parsed as
|
||||
<code>(*p)++</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>defer</code> statement may be used to call a function after
|
||||
the function containing the <code>defer</code> statement returns.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
fd := open("filename")
|
||||
defer close(fd) // fd will be closed when this function returns.
|
||||
</pre>
|
||||
|
||||
<h2 id="Constants">Constants </h2>
|
||||
|
||||
<p>
|
||||
In Go constants may be <i>untyped</i>. This applies even to constants
|
||||
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
|
||||
is used within a context that
|
||||
requires a typed value. This permits constants to be used relatively
|
||||
freely without requiring general implicit type conversion.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var a uint
|
||||
f(a + 1) // untyped numeric constant "1" becomes typed as uint
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The language does not impose any limits on the size of an untyped
|
||||
numeric constant or constant expression. A limit is only applied when
|
||||
a constant is used where a type is required.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
const huge = 1 << 100
|
||||
f(huge >> 98)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Go does not support enums. Instead, you can use the special name
|
||||
<code>iota</code> in a single <code>const</code> declaration to get a
|
||||
series of increasing
|
||||
value. When an initialization expression is omitted for a <code>const</code>,
|
||||
it reuses the preceding expression.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
const (
|
||||
red = iota // red == 0
|
||||
blue // blue == 1
|
||||
green // green == 2
|
||||
)
|
||||
</pre>
|
||||
|
||||
<h2 id="Slices">Slices</h2>
|
||||
|
||||
<p>
|
||||
A slice is conceptually a struct with three fields: a
|
||||
pointer to an array, a length, and a capacity.
|
||||
Slices support
|
||||
the <code>[]</code> operator to access elements of the underlying array.
|
||||
The builtin
|
||||
<code>len</code> function returns the
|
||||
length of the slice. The builtin <code>cap</code> function returns the
|
||||
capacity.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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 before index
|
||||
<code>j</code>. It has length <code>j-i</code>.
|
||||
If <code>i</code> is omitted, the slice starts at <code>0</code>.
|
||||
If <code>j</code> is omitted, the slice ends at <code>len(a)</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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
What this means is that Go uses slices for some cases where C++ uses pointers.
|
||||
If you create a value of type <code>[100]byte</code> (an array of 100 bytes,
|
||||
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 a slice of the array (<code>a[:]</code> will pass the entire array).
|
||||
Unlike in C++, it is not
|
||||
necessary to pass the length of the buffer; it is efficiently accessible via
|
||||
<code>len</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The slice syntax may also be used with a string. It returns a new string,
|
||||
whose value is a substring of the original string.
|
||||
Because strings are immutable, string slices can be implemented
|
||||
without allocating new storage for the slices's contents.
|
||||
</p>
|
||||
|
||||
<h2 id="Making_values">Making values</h2>
|
||||
|
||||
<p>
|
||||
Go has a builtin function <code>new</code> which takes a type and
|
||||
allocates space
|
||||
on the heap. The allocated space will be zero-initialized for the type.
|
||||
For example, <code>new(int)</code> allocates a new int on the heap,
|
||||
initializes it with the value <code>0</code>,
|
||||
and returns its address, which has type <code>*int</code>.
|
||||
Unlike in C++, <code>new</code> is a function, not an operator;
|
||||
<code>new int</code> is a syntax error.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Perhaps surprisingly, <code>new</code> is not commonly used in Go
|
||||
programs. In Go taking the address of a variable is always safe and
|
||||
never yields a dangling pointer. If the program takes the address of
|
||||
a variable, it will be allocated on the heap if necessary. So these
|
||||
functions are equivalent:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type S { I int }
|
||||
|
||||
func f1() *S {
|
||||
return new(S)
|
||||
}
|
||||
|
||||
func f2() *S {
|
||||
var s S
|
||||
return &s
|
||||
}
|
||||
|
||||
func f3() *S {
|
||||
// More idiomatic: use composite literal syntax.
|
||||
return &S{0}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Map and channel values must be allocated using the builtin function
|
||||
<code>make</code>.
|
||||
A variable declared with map or channel type without an initializer will be
|
||||
automatically initialized to <code>nil</code>.
|
||||
Calling <code>make(map[int]int)</code> returns a newly allocated value of
|
||||
type <code>map[int]int</code>.
|
||||
Note that <code>make</code> returns a value, not a pointer. This is
|
||||
consistent with
|
||||
the fact that map and channel values are passed by reference. Calling
|
||||
<code>make</code> with
|
||||
a map type takes an optional argument which is the expected capacity of the
|
||||
map. Calling <code>make</code> with a channel type takes an optional
|
||||
argument which sets the
|
||||
buffering capacity of the channel; the default is 0 (unbuffered).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <code>make</code> function may also be used to allocate a slice.
|
||||
In this case it
|
||||
allocates memory for the underlying array and returns a slice referring to it.
|
||||
There is one required argument, which is the number of elements in the slice.
|
||||
A second, optional, argument is the capacity of the slice. For example,
|
||||
<code>make([]int, 10, 20)</code>. This is identical to
|
||||
<code>new([20]int)[0:10]</code>. Since
|
||||
Go uses garbage collection, the newly allocated array will be discarded
|
||||
sometime after there are no references to the returned slice.
|
||||
</p>
|
||||
|
||||
<h2 id="Interfaces">Interfaces</h2>
|
||||
|
||||
<p>
|
||||
Where C++ provides classes, subclasses and templates,
|
||||
Go provides interfaces. A
|
||||
Go interface is similar to a C++ pure abstract class: a class with no
|
||||
data members, with methods which are all pure virtual. However, in
|
||||
Go, any type which provides the methods named in the interface may be
|
||||
treated as an implementation of the interface. No explicitly declared
|
||||
inheritance is required. The implementation of the interface is
|
||||
entirely separate from the interface itself.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
A method looks like an ordinary function definition, except that it
|
||||
has a <em>receiver</em>. The receiver is similar to
|
||||
the <code>this</code> pointer in a C++ class method.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type myType struct { i int }
|
||||
func (p *myType) Get() int { return p.i }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This declares a method <code>Get</code> associated with <code>myType</code>.
|
||||
The receiver is named <code>p</code> in the body of the function.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Methods are defined on named types. If you convert the value
|
||||
to a different type, the new value will have the methods of the new type,
|
||||
not the old type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You may define methods on a builtin type by declaring a new named type
|
||||
derived from it. The new type is distinct from the builtin type.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type myInteger int
|
||||
func (p myInteger) Get() int { return int(p) } // Conversion required.
|
||||
func f(i int) { }
|
||||
var v myInteger
|
||||
// f(v) is invalid.
|
||||
// f(int(v)) is valid; int(v) has no defined methods.
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Given this interface:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type myInterface interface {
|
||||
Get() int
|
||||
Set(i int)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
we can make <code>myType</code> satisfy the interface by adding
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func (p *myType) Set(i int) { p.i = i }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Now any function which takes <code>myInterface</code> as a parameter
|
||||
will accept a
|
||||
variable of type <code>*myType</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func GetAndSet(x myInterface) {}
|
||||
func f1() {
|
||||
var p myType
|
||||
GetAndSet(&p)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
In other words, if we view <code>myInterface</code> as a C++ pure abstract
|
||||
base
|
||||
class, defining <code>Set</code> and <code>Get</code> for
|
||||
<code>*myType</code> made <code>*myType</code> automatically
|
||||
inherit from <code>myInterface</code>. A type may satisfy multiple interfaces.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
An anonymous field may be used to implement something much like a C++ child
|
||||
class.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type myChildType struct { myType; j int }
|
||||
func (p *myChildType) Get() int { p.j++; return p.myType.Get() }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
This effectively implements <code>myChildType</code> as a child of
|
||||
<code>myType</code>.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func f2() {
|
||||
var p myChildType
|
||||
GetAndSet(&p)
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The <code>set</code> method is effectively inherited from
|
||||
<code>myType</code>, because
|
||||
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>.
|
||||
In this example, the <code>Get</code> method was
|
||||
overridden, and the <code>Set</code> method was inherited.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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>
|
||||
|
||||
<p>
|
||||
A variable that has an interface type may be converted to have a
|
||||
different interface type using a special construct called a type assertion.
|
||||
This is implemented dynamically
|
||||
at run time, like C++ <code>dynamic_cast</code>. Unlike
|
||||
<code>dynamic_cast</code>, there does
|
||||
not need to be any declared relationship between the two interfaces.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type myPrintInterface interface {
|
||||
Print()
|
||||
}
|
||||
func f3(x myInterface) {
|
||||
x.(myPrintInterface).Print() // type assertion to myPrintInterface
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The conversion to <code>myPrintInterface</code> is entirely dynamic.
|
||||
It will
|
||||
work as long as the underlying type of x (the <em>dynamic type</em>) defines
|
||||
a <code>print</code> method.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Because the conversion is dynamic, it may be used to implement generic
|
||||
programming similar to templates in C++. This is done by
|
||||
manipulating values of the minimal interface.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type Any interface { }
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Containers may be written in terms of <code>Any</code>, but the caller
|
||||
must unbox using a type assertion to recover
|
||||
values of the contained type. As the typing is dynamic rather
|
||||
than static, there is no equivalent of the way that a C++ template may
|
||||
inline the relevant operations. The operations are fully type-checked
|
||||
at run time, but all operations will involve a function call.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type Iterator interface {
|
||||
Get() Any
|
||||
Set(v Any)
|
||||
Increment()
|
||||
Equal(arg Iterator) bool
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Note that <code>Equal</code> has an argument of
|
||||
type <code>Iterator</code>. This does not behave like a C++
|
||||
template. See <a href="go_faq.html#t_and_equal_interface">the
|
||||
FAQ</a>.
|
||||
</p>
|
||||
|
||||
<h2 id="Goroutines">Goroutines</h2>
|
||||
|
||||
<p>
|
||||
Go permits starting a new thread of execution (a <em>goroutine</em>)
|
||||
using the <code>go</code>
|
||||
statement. The <code>go</code> statement runs a function in a
|
||||
different, newly created, goroutine.
|
||||
All goroutines in a single program share the same address space.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Internally, goroutines act like coroutines that are multiplexed among
|
||||
multiple operating system threads. You do not have to worry
|
||||
about these details.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func server(i int) {
|
||||
for {
|
||||
fmt.Print(i)
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
}
|
||||
go server(1)
|
||||
go server(2)
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
(Note that the <code>for</code> statement in the <code>server</code>
|
||||
function is equivalent to a C++ <code>while (true)</code> loop.)
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Goroutines are (intended to be) cheap.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Function literals (which Go implements as closures)
|
||||
can be useful with the <code>go</code> statement.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
var g int
|
||||
go func(i int) {
|
||||
s := 0
|
||||
for j := 0; j < i; j++ { s += j }
|
||||
g = s
|
||||
}(1000) // Passes argument 1000 to the function literal.
|
||||
</pre>
|
||||
|
||||
<h2 id="Channels">Channels</h2>
|
||||
|
||||
<p>
|
||||
Channels are used to communicate between goroutines. Any value may be
|
||||
sent over a channel. Channels are (intended to be) efficient and
|
||||
cheap. To send a value on a channel, use <code><-</code> as a binary
|
||||
operator. To
|
||||
receive a value on a channel, use <code><-</code> as a unary operator.
|
||||
When calling
|
||||
functions, channels are passed by reference.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The Go library provides mutexes, but you can also use
|
||||
a single goroutine with a shared channel.
|
||||
Here is an example of using a manager function to control access to a
|
||||
single value.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type Cmd struct { Get bool; Val int }
|
||||
func Manager(ch chan Cmd) {
|
||||
val := 0
|
||||
for {
|
||||
c := <-ch
|
||||
if c.Get { c.Val = val; ch <- c }
|
||||
else { val = c.Val }
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
type Cmd2 struct { Get bool; Val int; Ch <- chan int }
|
||||
func Manager2(ch chan Cmd2) {
|
||||
val := 0
|
||||
for {
|
||||
c := <-ch
|
||||
if c.Get { c.ch <- val }
|
||||
else { val = c.Val }
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
To use <code>Manager2</code>, given a channel to it:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
func f4(ch <- chan Cmd2) int {
|
||||
myCh := make(chan int)
|
||||
c := Cmd2{ true, 0, myCh } // Composite literal syntax.
|
||||
ch <- c
|
||||
return <-myCh
|
||||
}
|
||||
</pre>
|
Loading…
Reference in New Issue
Block a user