mirror of
https://github.com/golang/go.git
synced 2024-11-22 05:40:42 +00:00
Fix formatting.
parent
403f3c830e
commit
50e767626b
@ -1,25 +1,15 @@
|
||||
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.
|
||||
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.
|
||||
|
||||
An important point to keep in mind is that there are some fundamental differences in the thought processes required to be proficient in the two respective languages. Most formidably, C++'s object model is based on classes and class hierarchies while Go's object model is based on interfaces (and is essentially flat). Consequently, C++ design patterns rarely translate verbatim to Go. To program effectively in Go, one has to consider the _problem_ being solved, not the mechanisms one might use in C++ to solve the problem.
|
||||
|
||||
For a more general introduction to Go, see the
|
||||
<a href='http://tour.golang.org/'>Go Tour</a>,
|
||||
<a href='http://golang.org/doc/code.html'>How to Write Go Code</a>
|
||||
and <a href='http://golang.org/doc/effective_go.html'>Effective Go</a>.
|
||||
For a more general introduction to Go, see the <a href='http://tour.golang.org/'>Go Tour</a>, <a href='http://golang.org/doc/code.html'>How to Write Go Code</a> and <a href='http://golang.org/doc/effective_go.html'>Effective Go</a>.
|
||||
|
||||
For a detailed description of the Go language, see the
|
||||
<a href='http://golang.org/doc/go_spec.html'>Go spec</a>.
|
||||
For a detailed description of the Go language, see the <a href='http://golang.org/doc/go_spec.html'>Go spec</a>.
|
||||
|
||||
<h2>Conceptual Differences</h2>
|
||||
|
||||
<ul>
|
||||
<li>Go does not have classes with constructors or destructors. Instead of<br>
|
||||
class methods, a class inheritance hierarchy, and virtual functions, Go<br>
|
||||
provides <em>interfaces</em>, which are discussed in more detail below.<br>
|
||||
Interfaces are also used where C++ uses templates.</li>
|
||||
<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 discussed in more detail below. Interfaces are also used where C++ uses templates.</li>
|
||||
|
||||
<li>Go provides automatic garbage collection of allocated memory. It is not necessary (or possible) to release memory explicitly. There is no need to worry about heap-allocated vs. stack-allocated storage, <code>new</code> vs. <code>malloc</code>, or <code>delete</code> vs. <code>delete[]</code> vs. <code>free</code>. There is no need to separately manage <code>std::unique_ptr</code>, <code>std::shared_ptr</code>, <code>std::weak_ptr</code>, <code>std::auto_ptr</code>, and ordinary, non-smart "raw" pointers. Go's run-time system handles all of that error-prone code on the programmer's behalf.</li>
|
||||
|
||||
@ -27,33 +17,21 @@ Interfaces are also used where C++ uses templates.</li>
|
||||
|
||||
<li>Go is "safe" by default. Pointers cannot point to arbitrary memory, and buffer overruns result in crashes, not security exploits. The <code>unsafe</code> package lets programmers bypass some of Go's protection mechanisms where explicitly requested.</li>
|
||||
|
||||
<li>Arrays in Go are first class values. When an array is used as a function<br>
|
||||
parameter, the function receives a copy of the array, not a pointer to it.<br>
|
||||
However, in practice functions often use slices for parameters; slices hold<br>
|
||||
pointers to underlying arrays. Slices are discussed further below.</li>
|
||||
<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 discussed further below.</li>
|
||||
|
||||
<li>Strings are provided by the language. They may not be changed once they<br>
|
||||
have been created.</li>
|
||||
<li>Strings are provided by the language. They may not be changed once they have been created.</li>
|
||||
|
||||
<li>Hash tables are provided by the language. They are called maps.</li>
|
||||
|
||||
<li>Separate threads of execution, and communication channels between them, are<br>
|
||||
provided by the language. This is discussed further below.</li>
|
||||
<li>Separate threads of execution, and communication channels between them, are provided by the language. This is discussed further below.</li>
|
||||
|
||||
<li>Certain types (maps and channels, described further below) are passed by<br>
|
||||
reference, not by value. That is, passing a map to a function does not copy the<br>
|
||||
map, and if the function changes the map the change will be seen by the caller.<br>
|
||||
In C++ terms, one can think of these as being reference types.</li>
|
||||
<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>
|
||||
|
||||
<li>Go does not use header files. Instead, each source file is part of a<br>
|
||||
defined <em>package</em>. When a package defines an object (type, constant,<br>
|
||||
variable, function) with a name starting with an upper case letter, that object<br>
|
||||
is visible to any other file which imports that package.</li>
|
||||
<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>
|
||||
|
||||
<li>Go does not support implicit type conversion. Operations that mix different types require casts (called conversions in Go). This is true even of different user-defined aliases of the same underlying type.</li>
|
||||
|
||||
<li>Go does not support function overloading and does not support user defined<br>
|
||||
operators.</li>
|
||||
<li>Go does not support function overloading and does not support user defined operators.</li>
|
||||
|
||||
<li>Go does not support <code>const</code> or <code>volatile</code> qualifiers.</li>
|
||||
|
||||
@ -65,10 +43,7 @@ operators.</li>
|
||||
|
||||
<h2>Syntax</h2>
|
||||
|
||||
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. (` var v1 int ` → "Variable ` v1 ` is an ` int `.")
|
||||
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. (`var v1 int` → "Variable `v1` is an `int`.")
|
||||
|
||||
```go
|
||||
//Go C++
|
||||
@ -82,16 +57,9 @@ var v7 map[string]int // unordered_map<string, int>* v7; (approximately)
|
||||
var v8 func(a int) int // int (*v8)(int a);
|
||||
```
|
||||
|
||||
Declarations generally take the form of a keyword followed by the name
|
||||
of the object being declared. The keyword is one of ` var `,
|
||||
` func `,
|
||||
` const `, or ` type `. 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>.
|
||||
Declarations generally take the form of a keyword followed by the name of the object being declared. The keyword is one of `var`, `func`, `const`, or `type`. 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>.
|
||||
|
||||
You can also use a keyword followed by a series of declarations in
|
||||
parentheses.
|
||||
You can also use a keyword followed by a series of declarations in parentheses.
|
||||
|
||||
```go
|
||||
var (
|
||||
@ -100,31 +68,21 @@ var (
|
||||
)
|
||||
```
|
||||
|
||||
When declaring a function, you must either provide a name for each parameter
|
||||
or not provide a name for any parameter. (That is, C++ permits ` void f(int i, int); `, but Go does not permit the analogous ` func f(i int, int) `.) However, for convenience, in Go you may group several names with the same type:
|
||||
When declaring a function, you must either provide a name for each parameter or not provide a name for any parameter. (That is, C++ permits `void f(int i, int);`, but Go does not permit the analogous `func f(i int, int)`.) However, for convenience, in Go you may group several names with the same type:
|
||||
|
||||
```go
|
||||
func f(i, j, k int, s, t string)
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```go
|
||||
var v = *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
|
||||
(` 0 `, ` nil `, etc.). There are no
|
||||
uninitialized variables in Go.
|
||||
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 (`0`, `nil`, etc.). There are no uninitialized variables in Go.
|
||||
|
||||
Within a function, a short declaration syntax is available with
|
||||
` := ` .
|
||||
Within a function, a short declaration syntax is available with `:=` .
|
||||
|
||||
```go
|
||||
v1 := v2 // C++11: auto v1 = v2;
|
||||
@ -142,9 +100,7 @@ Go permits multiple assignments, which are done in parallel. That is, first all
|
||||
i, j = j, i // Swap i and j.
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```go
|
||||
func f() (i int, j int) { ... }
|
||||
@ -174,47 +130,30 @@ if result, ok := g(); !ok {
|
||||
…
|
||||
```
|
||||
|
||||
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='https://golang.org/ref/spec#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
|
||||
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='https://golang.org/ref/spec#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
|
||||
|
||||
```go
|
||||
func g()
|
||||
{ // INVALID
|
||||
}
|
||||
```
|
||||
A semicolon will be inserted after ` g() `, causing it to be
|
||||
a function declaration rather than a function definition. Similarly,
|
||||
you may not write
|
||||
|
||||
A semicolon will be inserted after `g()`, causing it to be a function declaration rather than a function definition. Similarly, you may not write
|
||||
|
||||
```go
|
||||
if x {
|
||||
}
|
||||
else { // INVALID
|
||||
}
|
||||
```
|
||||
A semicolon will be inserted after the ` } ` preceding
|
||||
the ` else `, causing a syntax error.
|
||||
|
||||
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 ` for ` loop clause and cases where you want several
|
||||
short statements on a single line.
|
||||
A semicolon will be inserted after the `}` preceding the `else`, causing a syntax error.
|
||||
|
||||
While we're on the topic, we recommend that rather than worry about
|
||||
semicolons and brace placement, you format your code with
|
||||
the ` gofmt ` 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.
|
||||
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 ` for ` loop clause and cases where you want several short statements on a single line.
|
||||
|
||||
When using a pointer to a struct, you use ` . ` instead
|
||||
of ` -> `.
|
||||
Thus, syntactically speaking, a structure and a pointer to a structure
|
||||
are used in the same way.
|
||||
While we're on the topic, we recommend that rather than worry about semicolons and brace placement, you format your code with the `gofmt` 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.
|
||||
|
||||
When using a pointer to a struct, you use `.` instead of `->`. Thus, syntactically speaking, a structure and a pointer to a structure are used in the same way.
|
||||
|
||||
```go
|
||||
type myStruct struct{ i int }
|
||||
@ -223,10 +162,7 @@ var p9 *myStruct // p9 is a pointer to a structure
|
||||
f(v9.i, p9.i)
|
||||
```
|
||||
|
||||
Go does not require parentheses around the condition of an ` if `
|
||||
statement, or the expressions of a ` for ` statement, or the value of a
|
||||
` switch ` statement. On the other hand, it does require curly braces
|
||||
around the body of an ` if ` or ` for ` statement.
|
||||
Go does not require parentheses around the condition of an `if` statement, or the expressions of a `for` statement, or the value of a `switch` statement. On the other hand, it does require curly braces around the body of an `if` or `for` statement.
|
||||
|
||||
```go
|
||||
if a < b { f() } // Valid
|
||||
@ -236,21 +172,11 @@ for i = 0; i < 10; i++ {} // Valid
|
||||
for (i = 0; i < 10; i++) {} // INVALID
|
||||
```
|
||||
|
||||
Go does not have a ` while ` statement nor does it have a
|
||||
` do/while `
|
||||
statement. The ` for ` statement may be used with a single condition,
|
||||
which makes it equivalent to a ` while ` statement. Omitting the
|
||||
condition entirely is an endless loop.
|
||||
Go does not have a `while` statement nor does it have a `do/while` statement. The `for` statement may be used with a single condition, which makes it equivalent to a `while` statement. Omitting the condition entirely is an endless loop.
|
||||
|
||||
Go permits ` break ` and ` continue ` to specify a label.
|
||||
The label must
|
||||
refer to a ` for `, ` switch `, or ` select `
|
||||
statement.
|
||||
Go permits `break` and `continue` to specify a label. The label must refer to a `for`, `switch`, or `select` statement.
|
||||
|
||||
In a ` switch ` statement, ` case ` labels do not fall
|
||||
through. You can
|
||||
make them fall through using the ` fallthrough ` keyword. This applies
|
||||
even to adjacent cases.
|
||||
In a `switch` statement, `case` labels do not fall through. You can make them fall through using the `fallthrough` keyword. This applies even to adjacent cases.
|
||||
|
||||
```go
|
||||
switch i {
|
||||
@ -260,7 +186,7 @@ case 1:
|
||||
}
|
||||
```
|
||||
|
||||
But a ` case ` can have multiple values.
|
||||
But a `case` can have multiple values.
|
||||
|
||||
```go
|
||||
switch i {
|
||||
@ -269,11 +195,7 @@ case 0, 1:
|
||||
}
|
||||
```
|
||||
|
||||
The values in a ` case ` 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 ` switch `
|
||||
value is omitted it defaults to ` true `.
|
||||
The values in a `case` 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 `switch` value is omitted it defaults to `true`.
|
||||
|
||||
```go
|
||||
switch {
|
||||
@ -286,7 +208,7 @@ case i > 0:
|
||||
}
|
||||
```
|
||||
|
||||
The ` defer ` statement may be used to call a function after the function containing the ` defer ` statement returns. ` defer ` often takes the place of a destructor in C++ but is associated with the calling code, not any particular class or object.
|
||||
The `defer` statement may be used to call a function after the function containing the `defer` statement returns. `defer` often takes the place of a destructor in C++ but is associated with the calling code, not any particular class or object.
|
||||
|
||||
```go
|
||||
fd := open("filename")
|
||||
@ -295,12 +217,10 @@ defer close(fd) // fd will be closed when this function returns.
|
||||
|
||||
<h2>Operators</h2>
|
||||
|
||||
The ` ++ ` and ` -- ` operators may only be used in
|
||||
statements, not in expressions.
|
||||
You cannot write ` c = *p++ `. ` *p++ ` is parsed as
|
||||
` (*p)++ `.
|
||||
The `++` and `--` operators may only be used in statements, not in expressions. You cannot write `c = *p++`. `*p++` is parsed as `(*p)++`.
|
||||
|
||||
The operator precedence is different. As an example `4 & 3 << 1` evaluates to `0` in Go and `4` in C++.
|
||||
|
||||
The operator precedence is different. As an example ` 4 & 3 << 1 ` evaluates to ` 0 ` in Go and ` 4 ` in C++.
|
||||
```
|
||||
Go operator precedence:
|
||||
1. * / % << >> & &^
|
||||
@ -324,37 +244,23 @@ C++ operator precedence (only relevant operators):
|
||||
10. ||
|
||||
```
|
||||
|
||||
<h2>Constants</h2>
|
||||
|
||||
<h2>Constants </h2>
|
||||
|
||||
In Go constants may be <i>untyped</i>. This applies even to constants
|
||||
named with a ` const ` 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.
|
||||
In Go constants may be <i>untyped</i>. This applies even to constants named with a `const` 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.
|
||||
|
||||
```go
|
||||
var a uint
|
||||
f(a + 1) // untyped numeric constant "1" becomes typed as uint
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```go
|
||||
const huge = 1 << 100
|
||||
f(huge >> 98)
|
||||
```
|
||||
|
||||
Go does not support enums. Instead, you can use the special name
|
||||
` iota ` in a single ` const ` declaration to get a
|
||||
series of increasing
|
||||
value. When an initialization expression is omitted for a ` const `,
|
||||
it reuses the preceding expression.
|
||||
Go does not support enums. Instead, you can use the special name `iota` in a single `const` declaration to get a series of increasing value. When an initialization expression is omitted for a `const`, it reuses the preceding expression.
|
||||
|
||||
```go
|
||||
const (
|
||||
@ -366,11 +272,11 @@ const (
|
||||
|
||||
<h2>Types</h2>
|
||||
|
||||
C++ and Go provide similar, but not identical, built-in types: signed and unsigned integers of various widths, 32-bit and 64-bit floating-point numbers (real and complex), ` struct `s, pointers, etc. In Go, ` uint8 `, ` int64 `, and like-named integer types are part of the language, not built on top of integers whose sizes are implementation-dependent (e.g., ` long long `). Go additionally provides native ` string `, ` map `, and ` channel ` types as well as first-class arrays and slices (described below). Strings are encoded with Unicode, not ASCII.
|
||||
C++ and Go provide similar, but not identical, built-in types: signed and unsigned integers of various widths, 32-bit and 64-bit floating-point numbers (real and complex), `struct`s, pointers, etc. In Go, `uint8`, `int64`, and like-named integer types are part of the language, not built on top of integers whose sizes are implementation-dependent (e.g., `long long`). Go additionally provides native `string`, `map`, and `chan` (channel) types as well as first-class arrays and slices (described below). Strings are encoded with Unicode, not ASCII.
|
||||
|
||||
Go is far more strongly typed than C++. In particular, there is no implicit type coercion in Go, only explicit type conversion. This provides additional safety and freedom from a class of bugs but at the cost of some additional typing. There is also no ` union ` type in Go, as this would enable subversion of the type system. However, a Go ` interface{} ` (see below) provides a type-safe alternative.
|
||||
Go is far more strongly typed than C++. In particular, there is no implicit type coercion in Go, only explicit type conversion. This provides additional safety and freedom from a class of bugs but at the cost of some additional typing. There is also no `union` type in Go, as this would enable subversion of the type system. However, a Go `interface{}` (see below) provides a type-safe alternative.
|
||||
|
||||
Both C++ and Go support type aliases (` typedef ` in C++, ` type ` in Go). However, unlike C++, Go treats these as different types. Hence, the following is valid in C++:
|
||||
Both C++ and Go support type aliases (`typedef` in C++, `type` in Go). However, unlike C++, Go treats these as different types. Hence, the following is valid in C++:
|
||||
|
||||
```C++
|
||||
// C++
|
||||
@ -396,68 +302,26 @@ pos += vel // INVALID: mismatched types position and velocity
|
||||
// pos += position(vel) // Valid
|
||||
```
|
||||
|
||||
The same is true even for unaliased types: an ` int ` and a ` uint ` cannot be combined in an expression without explicitly converting one to the other.
|
||||
The same is true even for unaliased types: an `int` and a `uint` cannot be combined in an expression without explicitly converting one to the other.
|
||||
|
||||
Go does not allow pointers to be cast to and from integers, unlike in C++. However, Go's ` unsafe ` package enables one to explicitly bypass this safety mechanism if necessary (e.g., for use in low-level systems code).
|
||||
Go does not allow pointers to be cast to and from integers, unlike in C++. However, Go's `unsafe` package enables one to explicitly bypass this safety mechanism if necessary (e.g., for use in low-level systems code).
|
||||
|
||||
|
||||
<h2>Slices</h2>
|
||||
|
||||
A slice is conceptually a struct with three fields: a
|
||||
pointer to an array, a length, and a capacity.
|
||||
Slices support
|
||||
the ` [] ` operator to access elements of the underlying array.
|
||||
The builtin
|
||||
` len ` function returns the
|
||||
length of the slice. The builtin ` cap ` function returns the
|
||||
capacity.
|
||||
A slice is conceptually a struct with three fields: a pointer to an array, a length, and a capacity. Slices support the `[]` operator to access elements of the underlying array. The builtin `len` function returns the length of the slice. The builtin `cap` function returns the capacity.
|
||||
|
||||
Given an array, or another slice, a new slice is created via
|
||||
` a[i:j] `. This
|
||||
creates a new slice which refers to ` a `, starts at
|
||||
index ` i `, and ends before index
|
||||
` j `. It has length ` j-i `.
|
||||
If ` i ` is omitted, the slice starts at ` 0 `.
|
||||
If ` j ` is omitted, the slice ends at ` len(a) `.
|
||||
The new slice refers to the same array
|
||||
to which ` a `
|
||||
refers. Two implications of this statement are that ① changes made using the new slice may be seen using
|
||||
` a `, and ② slice creation is (intended to be) cheap; no copy needs to be made of the underlying array. The
|
||||
capacity of the new slice is simply the capacity of ` a ` minus
|
||||
` i `. The capacity
|
||||
of an array is the length of the array.
|
||||
Given an array, or another slice, a new slice is created via `a[i:j]`. This creates a new slice that refers to `a`, starts at index `i`, and ends before index `j`. It has length `j-i`. If `i` is omitted, the slice starts at `0`. If `j` is omitted, the slice ends at `len(a)`. The new slice refers to the same array to which `a` refers. Two implications of this statement are that ① changes made using the new slice may be seen using `a`, and ② slice creation is (intended to be) cheap; no copy needs to be made of the underlying array. The capacity of the new slice is simply the capacity of `a` minus `i`. The capacity of an array is the length of the array.
|
||||
|
||||
What this means is that Go uses slices for some cases where C++ uses pointers.
|
||||
If you create a value of type ` [100]byte ` (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 ` []byte `, and
|
||||
pass a slice of the array (` a[:] ` will pass the entire array).
|
||||
Unlike in C++, it is not
|
||||
necessary to pass the length of the buffer; it is efficiently accessible via
|
||||
` len `.
|
||||
What this means is that Go uses slices for some cases where C++ uses pointers. If you create a value of type `[100]byte` (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 `[]byte`, and pass a slice of the array (`a[:]` will pass the entire array). Unlike in C++, it is not necessary to pass the length of the buffer; it is efficiently accessible via `len`.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
<h2>Making values</h2>
|
||||
|
||||
Go has a builtin function ` new ` which takes a type and
|
||||
allocates space
|
||||
on the heap. The allocated space will be zero-initialized for the type.
|
||||
For example, ` new(int) ` allocates a new int on the heap,
|
||||
initializes it with the value ` 0 `,
|
||||
and returns its address, which has type ` *int `.
|
||||
Unlike in C++, ` new ` is a function, not an operator;
|
||||
` new int ` is a syntax error.
|
||||
Go has a builtin function `new` which takes a type and allocates space on the heap. The allocated space will be zero-initialized for the type. For example, `new(int)` allocates a new int on the heap, initializes it with the value `0`, and returns its address, which has type `*int`. Unlike in C++, `new` is a function, not an operator; `new int` is a syntax error.
|
||||
|
||||
Perhaps surprisingly, ` new ` 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:
|
||||
Perhaps surprisingly, `new` 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:
|
||||
|
||||
```go
|
||||
type S struct { I int }
|
||||
@ -487,45 +351,15 @@ S* f2() {
|
||||
}
|
||||
```
|
||||
|
||||
Map and channel values must be allocated using the builtin function
|
||||
` make `.
|
||||
A variable declared with map or channel type without an initializer will be
|
||||
automatically initialized to ` nil `.
|
||||
Calling ` make(map[int]int) ` returns a newly allocated value of
|
||||
type ` map[int]int `.
|
||||
Note that ` make ` returns a value, not a pointer. This is
|
||||
consistent with
|
||||
the fact that map and channel values are passed by reference. Calling
|
||||
` make ` with
|
||||
a map type takes an optional argument which is the expected capacity of the
|
||||
map. Calling ` make ` with a channel type takes an optional
|
||||
argument which sets the
|
||||
buffering capacity of the channel; the default is 0 (unbuffered).
|
||||
Map and channel values must be allocated using the builtin function `make`. A variable declared with map or channel type without an initializer will be automatically initialized to `nil`. Calling `make(map[int]int)` returns a newly allocated value of type `map[int]int`. Note that `make` returns a value, not a pointer. This is consistent with the fact that map and channel values are passed by reference. Calling `make` with a map type takes an optional argument which is the expected capacity of the map. Calling `make` with a channel type takes an optional argument which sets the buffering capacity of the channel; the default is 0 (unbuffered).
|
||||
|
||||
The ` make ` 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,
|
||||
` make([]int, 10, 20) `. This is identical to
|
||||
` new([20]int)[0:10] `. Since
|
||||
Go uses garbage collection, the newly allocated array will be discarded
|
||||
sometime after there are no references to the returned slice.
|
||||
The `make` 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, `make([]int, 10, 20)`. This is identical to `new([20]int)[0:10]`. Since Go uses garbage collection, the newly allocated array will be discarded sometime after there are no references to the returned slice.
|
||||
|
||||
<h2>Interfaces</h2>
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
A method looks like an ordinary function definition, except that it
|
||||
has a <em>receiver</em>. The receiver is similar to
|
||||
the ` this ` pointer in a C++ class method.
|
||||
A method looks like an ordinary function definition, except that it has a <em>receiver</em>. The receiver is similar to the `this` pointer in a C++ class method.
|
||||
|
||||
```go
|
||||
type myType struct{ i int }
|
||||
@ -533,15 +367,12 @@ type myType struct{ i int }
|
||||
func (p *myType) Get() int { return p.i }
|
||||
```
|
||||
|
||||
This declares a method ` Get ` associated with ` myType `.
|
||||
The receiver is named ` p ` in the body of the function.
|
||||
This declares a method `Get` associated with `myType`. The receiver is named `p` in the body of the function.
|
||||
|
||||
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,
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```go
|
||||
type myInteger int
|
||||
@ -564,15 +395,13 @@ type myInterface interface {
|
||||
}
|
||||
```
|
||||
|
||||
we can make ` myType ` satisfy the interface by adding
|
||||
we can make `myType` satisfy the interface by adding
|
||||
|
||||
```go
|
||||
func (p *myType) Set(i int) { p.i = i }
|
||||
```
|
||||
|
||||
Now any function which takes ` myInterface ` as a parameter
|
||||
will accept a
|
||||
variable of type ` *myType `.
|
||||
Now any function which takes `myInterface` as a parameter will accept a variable of type `*myType`.
|
||||
|
||||
```go
|
||||
func GetAndSet(x myInterface) {}
|
||||
@ -582,14 +411,9 @@ func f1() {
|
||||
}
|
||||
```
|
||||
|
||||
In other words, if we view ` myInterface ` as a C++ pure abstract
|
||||
base
|
||||
class, defining ` Set ` and ` Get ` for
|
||||
` *myType ` made ` *myType ` automatically
|
||||
inherit from ` myInterface `. A type may satisfy multiple interfaces.
|
||||
In other words, if we view `myInterface` as a C++ pure abstract base class, defining `Set` and `Get` for `*myType` made `*myType` automatically inherit from `myInterface`. A type may satisfy multiple interfaces.
|
||||
|
||||
An anonymous field may be used to implement something much like a C++ child
|
||||
class.
|
||||
An anonymous field may be used to implement something much like a C++ child class.
|
||||
|
||||
```go
|
||||
type myChildType struct {
|
||||
@ -600,8 +424,7 @@ type myChildType struct {
|
||||
func (p *myChildType) Get() int { p.j++; return p.myType.Get() }
|
||||
```
|
||||
|
||||
This effectively implements ` myChildType ` as a child of
|
||||
` myType `.
|
||||
This effectively implements `myChildType` as a child of `myType`.
|
||||
|
||||
```go
|
||||
func f2() {
|
||||
@ -610,27 +433,11 @@ func f2() {
|
||||
}
|
||||
```
|
||||
|
||||
The ` Set ` method is effectively inherited from
|
||||
` myType `, because
|
||||
methods associated with the anonymous field are promoted to become methods
|
||||
of the enclosing type. In this case, because ` myChildType ` has an
|
||||
anonymous field of type ` myType `, the methods of
|
||||
` myType ` also become methods of ` myChildType `.
|
||||
In this example, the ` Get ` method was
|
||||
overridden, and the ` Set ` method was inherited.
|
||||
The `Set` method is effectively inherited from `myType`, because methods associated with the anonymous field are promoted to become methods of the enclosing type. In this case, because `myChildType` has an anonymous field of type `myType`, the methods of `myType` also become methods of `myChildType`. In this example, the `Get` method was overridden, and the `Set` method was inherited.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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++ ` dynamic_cast `. Unlike
|
||||
` dynamic_cast `, there does
|
||||
not need to be any declared relationship between the two interfaces.
|
||||
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++ `dynamic_cast`. Unlike `dynamic_cast`, there does not need to be any declared relationship between the two interfaces.
|
||||
|
||||
```go
|
||||
type myPrintInterface interface {
|
||||
@ -642,25 +449,15 @@ func f3(x myInterface) {
|
||||
}
|
||||
```
|
||||
|
||||
The conversion to ` myPrintInterface ` is entirely dynamic.
|
||||
It will
|
||||
work as long as the dynamic type of x defines
|
||||
a ` print ` method.
|
||||
The conversion to `myPrintInterface` is entirely dynamic. It will work as long as the dynamic type of x defines a `print` method.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```go
|
||||
type Any interface{}
|
||||
```
|
||||
|
||||
Containers may be written in terms of ` Any `, 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.
|
||||
Containers may be written in terms of `Any`, 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.
|
||||
|
||||
```go
|
||||
type Iterator interface {
|
||||
@ -671,13 +468,11 @@ type Iterator interface {
|
||||
}
|
||||
```
|
||||
|
||||
Note that ` Equal ` has an argument of
|
||||
type ` Iterator `. This does not behave like a C++
|
||||
template. See <a href='go_faq.html#t_and_equal_interface'>the FAQ</a>.
|
||||
Note that `Equal` has an argument of type `Iterator`. This does not behave like a C++ template. See <a href='go_faq.html#t_and_equal_interface'>the FAQ</a>.
|
||||
|
||||
<h2>Function closures</h2>
|
||||
|
||||
In C++ versions prior to C++11, the most common way to create a function with hidden state is to use a "functor"—a class that overloads ` operator() ` to make instances look like functions. For example, the following code defines a ` my_transform ` function (a simplified version of the STL's ` std::transform `) that applies a given unary operator (` op `) to each element of an array (` in `), storing the result in another array (` out `). To implement a prefix sum (i.e., {` x[0] `, ` x[0]+x[1] `, ` x[0]+x[1]+x[2] `, …}) the code creates a functor (` MyFunctor `) that keeps track of the running total (` total `) and passes an instance of this functor to ` my_transform `.
|
||||
In C++ versions prior to C++11, the most common way to create a function with hidden state is to use a "functor"—a class that overloads `operator()` to make instances look like functions. For example, the following code defines a `my_transform` function (a simplified version of the STL's `std::transform`) that applies a given unary operator (`op`) to each element of an array (`in`), storing the result in another array (`out`). To implement a prefix sum (i.e., {`x[0]`, `x[0]+x[1]`, `x[0]+x[1]+x[2]`, …}) the code creates a functor (`MyFunctor`) that keeps track of the running total (`total`) and passes an instance of this functor to `my_transform`.
|
||||
|
||||
```C++
|
||||
// C++
|
||||
@ -718,7 +513,7 @@ int main (void)
|
||||
}
|
||||
```
|
||||
|
||||
C++11 adds anonymous ("lambda") functions, which can be stored in variables and passed to functions. They can optionally serve as closures, meaning they can reference state from parent scopes. This feature greatly simplifies ` my_transform `:
|
||||
C++11 adds anonymous ("lambda") functions, which can be stored in variables and passed to functions. They can optionally serve as closures, meaning they can reference state from parent scopes. This feature greatly simplifies `my_transform`:
|
||||
|
||||
```C++
|
||||
// C++11
|
||||
@ -752,7 +547,7 @@ int main (void)
|
||||
}
|
||||
```
|
||||
|
||||
A typical Go version of ` my_transform ` looks a lot like the C++11 version:
|
||||
A typical Go version of `my_transform` looks a lot like the C++11 version:
|
||||
|
||||
```go
|
||||
package main
|
||||
@ -777,14 +572,14 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
(Note that we chose to return ` out ` from ` my_transform ` rather than pass it an ` out ` to write to. This was an aesthetic decision; the code could have been written more like the C++ version in that regard.)
|
||||
(Note that we chose to return `out` from `my_transform` rather than pass it an `out` to write to. This was an aesthetic decision; the code could have been written more like the C++ version in that regard.)
|
||||
|
||||
In Go, functions are always full closures, the equivalent of ` [&] ` in C++11. An important difference is that it is invalid in C++11 for a closure to reference a variable whose scope has gone away (as may be caused by an <a href='http://en.wikipedia.org/wiki/Funarg_problem'>upward funarg</a>—a function that returns a lambda that references local variables). In Go, this is perfectly valid.
|
||||
In Go, functions are always full closures, the equivalent of `[&]` in C++11. An important difference is that it is invalid in C++11 for a closure to reference a variable whose scope has gone away (as may be caused by an <a href='http://en.wikipedia.org/wiki/Funarg_problem'>upward funarg</a>—a function that returns a lambda that references local variables). In Go, this is perfectly valid.
|
||||
|
||||
|
||||
<h2>Concurrency</h2>
|
||||
|
||||
Like C++11's ` std::thread `, Go permits starting new threads of execution that run concurrently in a shared address space. These are called _goroutines_ and are spawned using the ` go ` statement. While typical ` std::thread ` implementations launch heavyweight, operating-system threads, goroutines are implemented as lightweight, user-level threads that are multiplexed among multiple operating-system threads. Consequently, goroutines are (intended to be) cheap and can be used liberally throughout a program.
|
||||
Like C++11's `std::thread`, Go permits starting new threads of execution that run concurrently in a shared address space. These are called _goroutines_ and are spawned using the `go` statement. While typical `std::thread` implementations launch heavyweight, operating-system threads, goroutines are implemented as lightweight, user-level threads that are multiplexed among multiple operating-system threads. Consequently, goroutines are (intended to be) cheap and can be used liberally throughout a program.
|
||||
|
||||
```go
|
||||
func server(i int) {
|
||||
@ -797,11 +592,9 @@ go server(1)
|
||||
go server(2)
|
||||
```
|
||||
|
||||
(Note that the ` for ` statement in the ` server `
|
||||
function is equivalent to a C++ ` while (true) ` loop.)
|
||||
(Note that the `for` statement in the `server` function is equivalent to a C++ `while (true)` loop.)
|
||||
|
||||
Function literals (which Go implements as closures)
|
||||
can be useful with the ` go ` statement.
|
||||
Function literals (which Go implements as closures) can be useful with the `go` statement.
|
||||
|
||||
```go
|
||||
var g int
|
||||
@ -814,8 +607,7 @@ go func(i int) {
|
||||
}(1000) // Passes argument 1000 to the function literal.
|
||||
```
|
||||
|
||||
Like C++11, but unlike prior versions of C++, Go defines a
|
||||
<a href='http://golang.org/ref/mem'>memory model</a> for unsynchronized accesses to memory. Although Go provides an analogue of ` std::mutex ` in its ` sync ` package, this is not the normal way to implement inter-thread communication and synchronization in Go programs. Instead, Go threads more typically communicate by message passing, which is a fundamentally different approach from locks and barriers. The Go mantra for this subject is,
|
||||
Like C++11, but unlike prior versions of C++, Go defines a <a href='http://golang.org/ref/mem'>memory model</a> for unsynchronized accesses to memory. Although Go provides an analogue of `std::mutex` in its ` sync ` package, this is not the normal way to implement inter-thread communication and synchronization in Go programs. Instead, Go threads more typically communicate by message passing, which is a fundamentally different approach from locks and barriers. The Go mantra for this subject is,
|
||||
|
||||
> Do not communicate by sharing memory; instead, share memory by communicating.
|
||||
|
||||
@ -823,12 +615,11 @@ That is, _channels_ are used to communicate among goroutines. Values of any typ
|
||||
sent over a channel. Channels can be unbuffered or buffered (using a buffer length specified at channel-construction time).
|
||||
|
||||
Channels are first-class values; they can be stored in variables and passed to and from functions like any other value. (When supplied to
|
||||
functions, channels are passed by reference.) Channels are also typed: a ` chan int ` is different from a ` chan string `.
|
||||
functions, channels are passed by reference.) Channels are also typed: a `chan int` is different from a `chan string`.
|
||||
|
||||
Because they are so widely used in Go programs, channels are (intended to be) efficient and cheap. To send a value on a channel, use ` <- ` as a binary operator. To receive a value on a channel, use ` <- ` as a unary operator. Channels can be shared among multiple senders and multiple receivers and guarantee that each value sent is received by at most one receiver.
|
||||
Because they are so widely used in Go programs, channels are (intended to be) efficient and cheap. To send a value on a channel, use `<-` as a binary operator. To receive a value on a channel, use `<-` as a unary operator. Channels can be shared among multiple senders and multiple receivers and guarantee that each value sent is received by at most one receiver.
|
||||
|
||||
Here is an example of using a manager function to control access to a
|
||||
single value.
|
||||
Here is an example of using a manager function to control access to a single value.
|
||||
|
||||
```go
|
||||
type Cmd struct {
|
||||
@ -850,12 +641,7 @@ func Manager(ch chan Cmd) {
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
```go
|
||||
type Cmd2 struct {
|
||||
@ -877,7 +663,7 @@ func Manager2(ch <-chan Cmd2) {
|
||||
}
|
||||
```
|
||||
|
||||
To use ` Manager2 `, given a channel to it:
|
||||
To use `Manager2`, given a channel to it:
|
||||
|
||||
```go
|
||||
func getFromManagedChannel(ch chan<- Cmd2) int {
|
||||
|
Loading…
Reference in New Issue
Block a user