Merge pull request #819 from vCaesar/u11-pr

Fix some md error, Add en/0.1.x.md and 0.2.x.md syntax highlighting
This commit is contained in:
astaxie
2017-04-10 00:08:10 +08:00
committed by GitHub
13 changed files with 1013 additions and 970 deletions

View File

@@ -109,7 +109,7 @@ Ubuntu is the most popular desktop release version of Linux. It uses `apt-get` t
sudo apt-get update
sudo apt-get install golang-stable
###wget
### wget
```sh
wget https://storage.googleapis.com/golang/go1.8.linux-amd64.tar.gz

View File

@@ -74,6 +74,8 @@ Create a new application package called `mathapp`.
Write the following content to main.go.
```Go
//$GOPATH/src/mathapp/main.go source code.
package main
@@ -85,7 +87,8 @@ Write the following content to main.go.
func main() {
fmt.Printf("Hello, world. Sqrt(2) = %v\n", mymath.Sqrt(2))
}
```
To compile this application, you need to switch to the application directory, which in this case is `$GOPATH/src/mathapp`, then execute the `go install` command. Now you should see an executable file called `mathapp` was generated in the directory `$GOPATH/bin/`. To run this program, use the `./mathapp` command. You should see the following content in your terminal.
Hello world. Sqrt(2) = 1.414213562373095
@@ -116,9 +119,9 @@ After executing the above commands, the directory structure should look like fol
Actually, `go get` clones source code to the $GOPATH/src of the local file system, then executes `go install`.
You can use remote packages in the same way that we use local packages.
```Go
import "github.com/astaxie/beedb"
```
## Directory complete structure
If you've followed all of the above steps, your directory structure should now look like the following.

View File

@@ -468,7 +468,7 @@ Atom is an awesome text editor released as open source cross platform, built on
Download: https://atom.io/
##Gogland
## Gogland
Gogland is the codename for a new commercial IDE by JetBrains aimed at providing an ergonomic environment for Go development.

View File

@@ -1,6 +1,7 @@
## What makes Go different from other languages?
The Go programming language was created with one goal in mind, to be able to build scalable web-applications for large scale audiences in a large team. So that is the reason they made the language as standardized as possible, hence the `gofmt` tool and the strict usage guidelines to the language was for the sake of not having two factions in the developer base, in other languages there are religious wars on where to keep the opening brace?
```java
public static void main() {
@@ -11,6 +12,7 @@ The Go programming language was created with one goal in mind, to be able to bui
{
}
```
or for python should we use 4 spaces or 6 spaces or a tab or two tabs and other user preferences.
While this might seem to be a shallow problem at the top, but when the codebase grows and more and more people are working on the same code base, then it is difficult to maintain the code's "beauty", if you know python then you might be aware of PEP8, which is a set of guidelines about how to write elegant code. We live in a world where robots can drive a car, so we shouldn't just write code, we should write elegant code.
@@ -40,7 +42,7 @@ Before we start building an application in Go, we need to learn how to write a s
According to international practice, before you learn how to program in some languages, you will want to know how to write a program to print "Hello world".
Are you ready? Let's Go!
```Go
package main
import "fmt"
@@ -48,7 +50,7 @@ Are you ready? Let's Go!
func main() {
fmt.Printf("Hello, world or 你好,世界 or καλημ ́ρα κóσμ or こんにちは世界\n")
}
```
It prints following information.
Hello, world or 你好,世界 or καλημ ́ρα κóσμ or こんにちは世界
@@ -83,10 +85,11 @@ Each go file is in some package, and that package should be a distinct folder in
the thing here is that when your code is using some static files or something else, then you ought to run the binary from the root of the application as we see in the second line above, I am running the `main` binary *outside* the main package, sometimes you might wonder why your application isn't working then this might be one of the possible problems, please keep this in mind.
One thing you will notice here is that go doesn't see to use semi colons to end a statement, well, it does, just there is a minor catch, the programmer isn't expected to put semi colons, the compiler adds semi colons to the gocode when it compiles which is the reason that this (thankfully!) is a syntax error
```Go
func main ()
{
}
```
because the compiler adds a semi colon at the end of `main()` which is a syntax error and as stated above, it helps avoid religious wars, i wish they combine `vim` and `emacs` and create a universal editor which'll help save some more wars! But for now we'll learn Go.
## Conclusion

View File

@@ -7,118 +7,119 @@ In this section, we are going to teach you how to define constants, variables wi
There are many forms of syntax that can be used to define variables in Go.
The keyword `var` is the basic form to define variables, notice that Go puts the variable type `after` the variable name.
```Go
// define a variable with name “variableName” and type "type"
var variableName type
```
Define multiple variables.
```Go
// define three variables which types are "type"
var vname1, vname2, vname3 type
```
Define a variable with initial value.
```Go
// define a variable with name “variableName”, type "type" and value "value"
var variableName type = value
```
Define multiple variables with initial values.
```Go
/*
Define three variables with type "type", and initialize their values.
vname1 is v1, vname2 is v2, vname3 is v3
*/
var vname1, vname2, vname3 type = v1, v2, v3
```
Do you think that it's too tedious to define variables use the way above? Don't worry, because the Go team has also found
this to be a problem. Therefore if you want to define variables with initial values, we can just omit the variable type,
so the code will look like this instead:
```Go
/*
Define three variables without type "type", and initialize their values.
vname1 is v1vname2 is v2vname3 is v3
*/
var vname1, vname2, vname3 = v1, v2, v3
```
Well, I know this is still not simple enough for you. Let's see how we fix it.
```Go
/*
Define three variables without type "type" and without keyword "var", and initialize their values.
vname1 is v1vname2 is v2vname3 is v3
*/
vname1, vname2, vname3 := v1, v2, v3
```
Now it looks much better. Use `:=` to replace `var` and `type`, this is called a brief statement. But wait, it has one limitation: this form can only be used inside of functions. You will get compile errors if you try to use it outside of function bodies. Therefore, we usually use `var` to define global variables.
`_` (blank) is a special variable name. Any value that is given to it will be ignored. For example, we give `35` to `b`, and discard `34`.( ***This example just show you how it works. It looks useless here because we often use this symbol when we get function return values.*** )
```Go
_, b := 34, 35
```
If you don't use variables that you've defined in your program, the compiler will give you compilation errors. Try to compile the following code and see what happens.
```Go
package main
func main() {
var i int
}
```
## Constants
So-called constants are the values that are determined during compile time and you cannot change them during runtime. In Go, you can use number, boolean or string as types of constants.
Define constants as follows.
```Go
const constantName = value
// you can assign type of constants if it's necessary
const Pi float32 = 3.1415926
```
More examples.
```Go
const Pi = 3.1415926
const i = 10000
const MaxThread = 10
const prefix = "astaxie_"
```
## Elementary types
### Boolean
In Go, we use `bool` to define a variable as boolean type, the value can only be `true` or `false`, and `false` will be the default value. ( ***You cannot convert variables' type between number and boolean!*** )
```Go
// sample code
var isActive bool // global variable
var enabled, disabled = true, false // omit type of variables
// sample code
var isActive bool // global variable
var enabled, disabled = true, false // omit type of variables
func test() {
var available bool // local variable
valid := false // brief statement of variable
available = true // assign value to variable
}
func test() {
var available bool // local variable
valid := false // brief statement of variable
available = true // assign value to variable
}
```
### Numerical types
Integer types include both signed and unsigned integer types. Go has `int` and `uint` at the same time, they have same length, but specific length depends on your operating system. They use 32-bit in 32-bit operating systems, and 64-bit in 64-bit operating systems. Go also has types that have specific length including `rune`, `int8`, `int16`, `int32`, `int64`, `byte`, `uint8`, `uint16`, `uint32`, `uint64`. Note that `rune` is alias of `int32` and `byte` is alias of `uint8`.
One important thing you should know that you cannot assign values between these types, this operation will cause compile errors.
```Go
var a int8
var b int32
c := a + b
```
Although int32 has a longer length than int8, and has the same type as int, you cannot assign values between them. ( ***c will be asserted as type `int` here*** )
Float types have the `float32` and `float64` types and no type called `float`. The latter one is the default type if using brief statement.
That's all? No! Go supports complex numbers as well. `complex128` (with a 64-bit real and 64-bit imaginary part) is the default type, if you need a smaller type, there is one called `complex64` (with a 32-bit real and 32-bit imaginary part). Its form is `RE+IMi`, where `RE` is real part and `IM` is imaginary part, the last `i` is the imaginary number. There is a example of complex number.
```Go
var c complex64 = 5+5i
//output: (5+5i)
fmt.Printf("Value is: %v", c)
```
### String
We just talked about how Go uses the UTF-8 character set. Strings are represented by double quotes `""` or backticks ``` `` ```.
```Go
// sample code
var frenchHello string // basic form to define string
var emptyString string = "" // define a string with empty string
@@ -127,49 +128,49 @@ We just talked about how Go uses the UTF-8 character set. Strings are represente
japaneseHello := "Ohaiou"
frenchHello = "Bonjour" // basic form of assign values
}
```
It's impossible to change string values by index. You will get errors when you compile the following code.
```Go
var s string = "hello"
s[0] = 'c'
```
What if I really want to change just one character in a string? Try the following code.
```Go
s := "hello"
c := []byte(s) // convert string to []byte type
c[0] = 'c'
s2 := string(c) // convert back to string type
fmt.Printf("%s\n", s2)
```
You use the `+` operator to combine two strings.
```Go
s := "hello,"
m := " world"
a := s + m
fmt.Printf("%s\n", a)
```
and also.
```Go
s := "hello"
s = "c" + s[1:] // you cannot change string values by index, but you can get values instead.
fmt.Printf("%s\n", s)
```
What if I want to have a multiple-line string?
```Go
m := `hello
world`
```
``` ` ``` will not escape any characters in a string.
### Error types
Go has one `error` type for purpose of dealing with error messages. There is also a package called `errors` to handle errors.
```Go
err := errors.New("emit macho dwarf: elf header corrupted")
if err != nil {
fmt.Print(err)
}
```
### Underlying data structure
The following picture comes from an article about [Go data structure](http://research.swtch.com/godata) in [Russ Cox's Blog](http://research.swtch.com/). As you can see, Go utilizes blocks of memory to store data.
@@ -185,7 +186,7 @@ Figure 2.1 Go underlying data structure
If you want to define multiple constants, variables or import packages, you can use the group form.
Basic form.
```Go
import "fmt"
import "os"
@@ -196,9 +197,9 @@ Basic form.
var i int
var pi float32
var prefix string
```
Group form.
```Go
import(
"fmt"
"os"
@@ -215,13 +216,13 @@ Group form.
pi float32
prefix string
)
```
Unless you assign the value of constant is `iota`, the first value of constant in the group `const()` will be `0`. If following constants don't assign values explicitly, their values will be the same as the last one. If the value of last constant is `iota`, the values of following constants which are not assigned are `iota` also.
### iota enumerate
Go has one keyword called `iota`, this keyword is to make `enum`, it begins with `0`, increased by `1`.
```Go
const(
x = iota // x == 0
y = iota // y == 1
@@ -235,7 +236,7 @@ Go has one keyword called `iota`, this keyword is to make `enum`, it begins with
const (
e, f, g = iota, iota, iota // e=0,f=0,g=0 values of iota are same in one line.
)
```
### Some rules
The reason that Go is concise because it has some default behaviors.
@@ -248,11 +249,11 @@ The reason that Go is concise because it has some default behaviors.
### array
`array` is an array obviously, we define one as follows.
```Go
var arr [n]type
```
in `[n]type`, `n` is the length of the array, `type` is the type of its elements. Like other languages, we use `[]` to get or set element values within arrays.
```Go
var arr [10]int // an array of type [10]int
arr[0] = 42 // array is 0-based
arr[1] = 13 // assign value to element
@@ -260,11 +261,11 @@ in `[n]type`, `n` is the length of the array, `type` is the type of its elements
// get element value, it returns 42
fmt.Printf("The last element is %d\n", arr[9])
//it returns default value of 10th element in this array, which is 0 in this case.
```
Because length is a part of the array type, `[3]int` and `[4]int` are different types, so we cannot change the length of arrays. When you use arrays as arguments, functions get their copies instead of references! If you want to use references, you may want to use `slice`. We'll talk about later.
It's possible to use `:=` when you define arrays.
```Go
a := [3]int{1, 2, 3} // define an int array with 3 elements
b := [10]int{1, 2, 3}
@@ -272,15 +273,15 @@ It's possible to use `:=` when you define arrays.
//The rest of them use the default value 0.
c := [...]int{4, 5, 6} // use `…` to replace the length parameter and Go will calculate it for you.
```
You may want to use arrays as arrays' elements. Let's see how to do this.
```Go
// define a two-dimensional array with 2 elements, and each element has 4 elements.
doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}
// The declaration can be written more concisely as follows.
easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}
```
Array underlying data structure.
![](images/2.2.array.png?raw=true)
@@ -292,18 +293,18 @@ Figure 2.2 Multidimensional array mapping relationship
In many situations, the array type is not a good choice -for instance when we don't know how long the array will be when we define it. Thus, we need a "dynamic array". This is called `slice` in Go.
`slice` is not really a `dynamic array`. It's a reference type. `slice` points to an underlying `array` whose declaration is similar to `array`, but doesn't need length.
```Go
// just like defining an array, but this time, we exclude the length.
var fslice []int
```
Then we define a `slice`, and initialize its data.
```Go
slice := []byte {'a', 'b', 'c', 'd'}
```
`slice` can redefine existing slices or arrays. `slice` uses `array[i:j]` to slice, where `i` is
the start index and `j` is end index, but notice that `array[j]` will not be sliced since the length
of the slice is `j-i`.
```Go
// define an array with 10 elements whose types are bytes
var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
@@ -317,7 +318,7 @@ of the slice is `j-i`.
// 'b' is another slice of array ar
b = ar[3:5]
// now 'b' has elements ar[3] and ar[4]
```
Notice the differences between `slice` and `array` when you define them. We use `[]` to let Go
calculate length but use `[]` to define slice only.
@@ -334,7 +335,7 @@ slice has some convenient operations.
- You can use `ar[:]` to slice whole array, reasons are explained in first two statements.
More examples pertaining to `slice`
```Go
// define an array
var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
// define two slices
@@ -351,7 +352,7 @@ More examples pertaining to `slice`
bSlice = aSlice[:3] // bSlice contains aSlice[0], aSlice[1], aSlice[2], so it has d,e,f
bSlice = aSlice[0:5] // slice could be expanded in range of cap, now bSlice contains d,e,f,g,h
bSlice = aSlice[:] // bSlice has same elements as aSlice does, which are d,e,f,g
```
`slice` is a reference type, so any changes will affect other variables pointing to the same slice or array.
For instance, in the case of `aSlice` and `bSlice` above, if you change the value of an element in `aSlice`,
`bSlice` will be changed as well.
@@ -361,10 +362,10 @@ For instance, in the case of `aSlice` and `bSlice` above, if you change the valu
- A pointer that points to where `slice` starts.
- The length of `slice`.
- Capacity, the length from start index to end index of `slice`.
```Go
Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
Slice_a := Array_a[2:5]
```
The underlying data structure of the code above as follows.
![](images/2.2.slice2.png?raw=true)
@@ -389,7 +390,7 @@ this happens, other slices pointing to the old array will not be affected.
Let's see some code. The 'set' and 'get' values in `map` are similar to `slice`, however the index in `slice` can only be
of type 'int' while `map` can use much more than that: for example `int`, `string`, or whatever you want. Also, they are
all able to use `==` and `!=` to compare values.
```Go
// use string as the key type, int as the value type, and `make` initialize it.
var numbers map[string] int
// another way to define map
@@ -400,7 +401,7 @@ all able to use `==` and `!=` to compare values.
fmt.Println("The third number is: ", numbers["three"]) // get values
// It prints: The third number is: 3
```
Some notes when you use map.
- `map` is disorderly. Everytime you print `map` you will get different results. It's impossible to get values by `index` -you have to use `key`.
@@ -411,7 +412,7 @@ Some notes when you use map.
You can use form `key:val` to initialize map's values, and `map` has built-in methods to check if the `key` exists.
Use `delete` to delete an element in `map`.
```Go
// Initialize a map
rating := map[string]float32 {"C":5, "Go":4.5, "Python":4.5, "C++":2 }
// map has two return values. For the second return value, if the key doesn't
@@ -424,15 +425,15 @@ Use `delete` to delete an element in `map`.
}
delete(rating, "C") // delete element with key "c"
```
As I said above, `map` is a reference type. If two `map`s point to same underlying data,
any change will affect both of them.
```Go
m := make(map[string]string)
m["Hello"] = "Bonjour"
m1 := m
m1["Hello"] = "Salut" // now the value of m["hello"] is Salut
```
### make, new
`make` does memory allocation for built-in models, such as `map`, `slice`, and `channel`, while `new` is for types'
@@ -458,7 +459,7 @@ The following picture shows how `new` and `make` are different.
Figure 2.5 Underlying memory allocation of make and new
Zero-value does not mean empty value. It's the value that variables default to in most cases. Here is a list of some zero-values.
```Go
int 0
int8 0
int32 0
@@ -470,7 +471,7 @@ Zero-value does not mean empty value. It's the value that variables default to i
float64 0 //length is 8 byte
bool false
string ""
```
## Links
- [Directory](preface.md)

View File

@@ -11,15 +11,15 @@ The greatest invention in programming is flow control. Because of them, you are
`if` will most likely be the most common keyword in your programs. If it meets the conditions, then it does something and it does something else if not.
`if` doesn't need parentheses in Go.
```Go
if x > 10 {
fmt.Println("x is greater than 10")
} else {
fmt.Println("x is less than or equal to 10")
}
```
The most useful thing concerning `if` in Go is that it can have one initialization statement before the conditional statement. The scope of the variables defined in this initialization statement are only available inside the block of the defining `if`.
```Go
// initialize x, then check if x greater than
if x := computedValue(); x > 10 {
fmt.Println("x is greater than 10")
@@ -29,9 +29,9 @@ The most useful thing concerning `if` in Go is that it can have one initializati
// the following code will not compile
fmt.Println(x)
```
Use if-else for multiple conditions.
```Go
if integer == 3 {
fmt.Println("The integer is equal to 3")
} else if integer < 3 {
@@ -39,11 +39,11 @@ Use if-else for multiple conditions.
} else {
fmt.Println("The integer is greater than 3")
}
```
### goto
Go has a `goto` keyword, but be careful when you use it. `goto` reroutes the control flow to a previously defined `label` within the body of same code block.
```Go
func myFunc() {
i := 0
Here: // label ends with ":"
@@ -51,21 +51,21 @@ Go has a `goto` keyword, but be careful when you use it. `goto` reroutes the con
i++
goto Here // jump to label "Here"
}
```
The label name is case sensitive.
### for
`for` is the most powerful control logic in Go. It can read data in loops and iterative operations, just like `while`.
```Go
for expression1; expression2; expression3 {
//...
}
```
`expression1`, `expression2` and `expression3` are all expressions, where `expression1` and `expression3` are variable definitions or return values from functions, and `expression2` is a conditional statement. `expression1` will be executed once before looping, and `expression3` will be executed after each loop.
Examples are more useful than words.
```Go
package main
import "fmt"
@@ -77,25 +77,25 @@ Examples are more useful than words.
fmt.Println("sum is equal to ", sum)
}
// Printsum is equal to 45
```
Sometimes we need multiple assignments, but Go doesn't have the `,` operator, so we use parallel assignment like `i, j = i + 1, j - 1`.
We can omit `expression1` and `expression3` if they are not necessary.
```Go
sum := 1
for ; sum < 1000; {
sum += sum
}
```
Omit `;` as well. Feel familiar? Yes, it's identical to `while`.
```Go
sum := 1
for sum < 1000 {
sum += sum
}
```
There are two important operations in loops which are `break` and `continue`. `break` jumps out of the loop, and `continue` skips the current loop and starts the next one. If you have nested loops, use `break` along with labels.
```Go
for index := 10; index>0; index-- {
if index == 5{
break // or continue
@@ -104,14 +104,14 @@ There are two important operations in loops which are `break` and `continue`. `b
}
// break prints 10、9、8、7、6
// continue prints 10、9、8、7、6、4、3、2、1
```
`for` can read data from `slice` and `map` when it is used together with `range`.
```Go
for k,v:=range map {
fmt.Println("map's key:",k)
fmt.Println("map's val:",v)
}
```
Because Go supports multi-value returns and gives compile errors when you don't use values that were defined, you may want to use `_` to discard certain return values.
for _, v := range map{
@@ -121,7 +121,7 @@ Because Go supports multi-value returns and gives compile errors when you don't
### switch
Sometimes you may find that you are using too many `if-else` statements to implement some logic, which may make it difficult to read and maintain in the future. This is the perfect time to use the `switch` statement to solve this problem.
```Go
switch sExpr {
case expr1:
some instructions
@@ -132,9 +132,9 @@ Sometimes you may find that you are using too many `if-else` statements to imple
default:
other code
}
```
The type of `sExpr`, `expr1`, `expr2`, and `expr3` must be the same. `switch` is very flexible. Conditions don't have to be constants and it executes from top to bottom until it matches conditions. If there is no statement after the keyword `switch`, then it matches `true`.
```Go
i := 10
switch i {
case 1:
@@ -146,9 +146,9 @@ The type of `sExpr`, `expr1`, `expr2`, and `expr3` must be the same. `switch` is
default:
fmt.Println("All I know is that i is an integer")
}
```
In the fifth line, we put many values in one `case`, and we don't need to add the `break` keyword at the end of `case`'s body. It will jump out of the switch body once it matched any case. If you want to continue to matching more cases, you need to use the`fallthrough` statement.
```Go
integer := 6
switch integer {
case 4:
@@ -169,24 +169,24 @@ In the fifth line, we put many values in one `case`, and we don't need to add th
default:
fmt.Println("default case")
}
```
This program prints the following information.
```Go
integer <= 6
integer <= 7
integer <= 8
default case
```
## Functions
Use the `func` keyword to define a function.
```Go
func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) {
// function body
// multi-value return
return value1, value2
}
```
We can extrapolate the following information from the example above.
- Use keyword `func` to define a function `funcName`.
@@ -198,31 +198,33 @@ We can extrapolate the following information from the example above.
- If the function has return values, you have to use the `return` statement somewhere in the body of the function.
Let's see one practical example. (calculate maximum value)
```Go
package main
package main
import "fmt"
import "fmt"
// return greater value between a and b
func max(a, b int) int {
if a > b {
return a
}
return b
// return greater value between a and b
func max(a, b int) int {
if a > b {
return a
}
return b
}
func main() {
x := 3
y := 4
z := 5
func main() {
x := 3
y := 4
z := 5
max_xy := max(x, y) // call function max(x, y)
max_xz := max(x, z) // call function max(x, z)
max_xy := max(x, y) // call function max(x, y)
max_xz := max(x, z) // call function max(x, z)
fmt.Printf("max(%d, %d) = %d\n", x, y, max_xy)
fmt.Printf("max(%d, %d) = %d\n", x, z, max_xz)
fmt.Printf("max(%d, %d) = %d\n", y, z, max(y,z)) // call function here
}
fmt.Printf("max(%d, %d) = %d\n", x, y, max_xy)
fmt.Printf("max(%d, %d) = %d\n", x, z, max_xz)
fmt.Printf("max(%d, %d) = %d\n", y, z, max(y, z)) // call function here
}
```
In the above example, there are two arguments in the function `max`, their types are both `int` so the first type can be omitted. For instance, `a, b int` instead of `a int, b int`. The same rules apply for additional arguments. Notice here that `max` only has one return value, so we only need to write the type of its return value -this is the short form of writing it.
### Multi-value return
@@ -230,71 +232,73 @@ In the above example, there are two arguments in the function `max`, their types
One thing that Go is better at than C is that it supports multi-value returns.
We'll use the following example here.
```Go
package main
package main
import "fmt"
import "fmt"
// return results of A + B and A * B
func SumAndProduct(A, B int) (int, int) {
return A+B, A*B
}
// return results of A + B and A * B
func SumAndProduct(A, B int) (int, int) {
return A + B, A * B
}
func main() {
x := 3
y := 4
func main() {
x := 3
y := 4
xPLUSy, xTIMESy := SumAndProduct(x, y)
xPLUSy, xTIMESy := SumAndProduct(x, y)
fmt.Printf("%d + %d = %d\n", x, y, xPLUSy)
fmt.Printf("%d * %d = %d\n", x, y, xTIMESy)
}
fmt.Printf("%d + %d = %d\n", x, y, xPLUSy)
fmt.Printf("%d * %d = %d\n", x, y, xTIMESy)
}
```
The above example returns two values without names -you have the option of naming them also. If we named the return values, we would just need to use `return` to return the values since they are initialized in the function automatically. Notice that if your functions are going to be used outside of the package, which means your function names start with a capital letter, you'd better write complete statements for `return`; it makes your code more readable.
```Go
func SumAndProduct(A, B int) (add int, multiplied int) {
add = A+B
multiplied = A*B
return
}
```
### Variadic functions
Go supports functions with a variable number of arguments. These functions are called "variadic", which means the function allows an uncertain numbers of arguments.
```Go
func myfunc(arg ...int) {}
```
`arg …int` tells Go that this is a function that has variable arguments. Notice that these arguments are type `int`. In the body of function, the `arg` becomes a `slice` of `int`.
```Go
for _, n := range arg {
fmt.Printf("And the number is: %d\n", n)
}
```
### Pass by value and pointers
When we pass an argument to the function that was called, that function actually gets the copy of our variables so any change will not affect to the original variable.
Let's see one example in order to prove what i'm saying.
```Go
package main
package main
import "fmt"
import "fmt"
// simple function to add 1 to a
func add1(a int) int {
a = a+1 // we change value of a
return a // return new value of a
}
// simple function to add 1 to a
func add1(a int) int {
a = a + 1 // we change value of a
return a // return new value of a
}
func main() {
x := 3
func main() {
x := 3
fmt.Println("x = ", x) // should print "x = 3"
fmt.Println("x = ", x) // should print "x = 3"
x1 := add1(x) // call add1(x)
x1 := add1(x) // call add1(x)
fmt.Println("x+1 = ", x1) // should print "x+1 = 4"
fmt.Println("x = ", x) // should print "x = 3"
}
fmt.Println("x+1 = ", x1) // should print "x+1 = 4"
fmt.Println("x = ", x) // should print "x = 3"
}
```
Can you see that? Even though we called `add1` with `x`, the origin value of `x` doesn't change.
The reason is very simple: when we called `add1`, we gave a copy of `x` to it, not the `x` itself.
@@ -302,27 +306,29 @@ The reason is very simple: when we called `add1`, we gave a copy of `x` to it, n
Now you may ask how I can pass the real `x` to the function.
We need use pointers here. We know variables are stored in memory and they have some memory addresses. So, if we want to change the value of a variable, we must change its memory address. Therefore the function `add1` has to know the memory address of `x` in order to change its value. Here we pass `&x` to the function, and change the argument's type to the pointer type `*int`. Be aware that we pass a copy of the pointer, not copy of value.
```Go
package main
package main
import "fmt"
import "fmt"
// simple function to add 1 to a
func add1(a *int) int {
*a = *a+1 // we changed value of a
return *a // return new value of a
}
// simple function to add 1 to a
func add1(a *int) int {
*a = *a + 1 // we changed value of a
return *a // return new value of a
}
func main() {
x := 3
func main() {
x := 3
fmt.Println("x = ", x) // should print "x = 3"
fmt.Println("x = ", x) // should print "x = 3"
x1 := add1(&x) // call add1(&x) pass memory address of x
x1 := add1(&x) // call add1(&x) pass memory address of x
fmt.Println("x+1 = ", x1) // should print "x+1 = 4"
fmt.Println("x = ", x) // should print "x = 4"
}
fmt.Println("x+1 = ", x1) // should print "x+1 = 4"
fmt.Println("x = ", x) // should print "x = 4"
}
```
Now we can change the value of `x` in the functions. Why do we use pointers? What are the advantages?
- Allows us to use more functions to operate on one variable.
@@ -332,92 +338,94 @@ Now we can change the value of `x` in the functions. Why do we use pointers? Wha
### defer
Go has a well designed keyword called `defer`. You can have many `defer` statements in one function; they will execute in reverse order when the program executes to the end of functions. In the case where the program opens some resource files, these files would have to be closed before the function can return with errors. Let's see some examples.
func ReadWrite() bool {
file.Open("file")
```Go
func ReadWrite() bool {
file.Open("file")
// Do some work
if failureX {
file.Close()
return false
}
if failureY {
file.Close()
return false
}
file.Close()
return true
if failureX {
file.Close()
return false
}
if failureY {
file.Close()
return false
}
file.Close()
return true
}
```
We saw some code being repeated several times. `defer` solves this problem very well. It doesn't only help you to write clean code but also makes your code more readable.
func ReadWrite() bool {
file.Open("file")
defer file.Close()
if failureX {
return false
}
if failureY {
return false
}
return true
```Go
func ReadWrite() bool {
file.Open("file")
defer file.Close()
if failureX {
return false
}
if failureY {
return false
}
return true
}
```
If there are more than one `defer`s, they will execute by reverse order. The following example will print `4 3 2 1 0`.
```Go
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
```
### Functions as values and types
Functions are also variables in Go, we can use `type` to define them. Functions that have the same signature can be seen as the same type.
```Go
type typeName func(input1 inputType1 , input2 inputType2 [, ...]) (result1 resultType1 [, ...])
```
What's the advantage of this feature? The answer is that it allows us to pass functions as values.
```Go
package main
package main
import "fmt"
import "fmt"
type testInt func(int) bool // define a function type of variable
type testInt func(int) bool // define a function type of variable
func isOdd(integer int) bool {
if integer%2 == 0 {
return false
}
return true
func isOdd(integer int) bool {
if integer%2 == 0 {
return false
}
return true
}
func isEven(integer int) bool {
if integer%2 == 0 {
return true
}
return false
func isEven(integer int) bool {
if integer%2 == 0 {
return true
}
return false
}
// pass the function `f` as an argument to another function
// pass the function `f` as an argument to another function
func filter(slice []int, f testInt) []int {
var result []int
for _, value := range slice {
if f(value) {
result = append(result, value)
}
}
return result
func filter(slice []int, f testInt) []int {
var result []int
for _, value := range slice {
if f(value) {
result = append(result, value)
}
}
return result
}
func main(){
slice := []int {1, 2, 3, 4, 5, 7}
fmt.Println("slice = ", slice)
odd := filter(slice, isOdd) // use function as values
fmt.Println("Odd elements of slice are: ", odd)
even := filter(slice, isEven)
fmt.Println("Even elements of slice are: ", even)
}
func main() {
slice := []int{1, 2, 3, 4, 5, 7}
fmt.Println("slice = ", slice)
odd := filter(slice, isOdd) // use function as values
fmt.Println("Odd elements of slice are: ", odd)
even := filter(slice, isEven)
fmt.Println("Even elements of slice are: ", even)
}
```
It's very useful when we use interfaces. As you can see `testInt` is a variable that has a function as type and the returned values and arguments of `filter` are the same as those of `testInt`. Therefore, we can have complex logic in our programs, while maintaining flexibility in our code.
### Panic and Recover
@@ -429,7 +437,7 @@ Go doesn't have `try-catch` structure like Java does. Instead of throwing except
`Recover` is a built-in function to recover `goroutine`s from panic status. Calling `recover` in `defer` functions is useful because normal functions will not be executed when the program is in the panic status. It catches `panic` values if the program is in the panic status, and it gets `nil` if the program is not in panic status.
The following example shows how to use `panic`.
```Go
var user = os.Getenv("USER")
func init() {
@@ -437,9 +445,9 @@ The following example shows how to use `panic`.
panic("no value for $USER")
}
}
```
The following example shows how to check `panic`.
```Go
func throwsPanic(f func()) (b bool) {
defer func() {
if x := recover(); x != nil {
@@ -449,7 +457,7 @@ The following example shows how to check `panic`.
f() // if f causes panic, it will recover
return
}
```
### `main` function and `init` function
Go has two retentions which are called `main` and `init`, where `init` can be used in all packages and `main` can only be used in the `main` package. These two functions are not able to have arguments or return values. Even though we can write many `init` functions in one package, I strongly recommend writing only one `init` function for each package.
@@ -465,15 +473,15 @@ Figure 2.6 Flow of programs initialization in Go
### import
We use `import` very often in Go programs as follows.
```Go
import(
"fmt"
)
```
Then we use functions in that package as follows.
```Go
fmt.Println("hello world")
```
`fmt` is from Go standard library, it is located within $GOROOT/pkg. Go supports third-party packages in two ways.
1. Relative path
@@ -485,28 +493,28 @@ There are some special operators when we import packages, and beginners are alwa
1. Dot operator.
Sometime we see people use following way to import packages.
```Go
import(
. "fmt"
)
```
The dot operator means you can omit the package name when you call functions inside of that package. Now `fmt.Printf("Hello world")` becomes to `Printf("Hello world")`.
2. Alias operation.
It changes the name of the package that we imported when we call functions that belong to that package.
```Go
import(
f "fmt"
)
```
Now `fmt.Printf("Hello world")` becomes to `f.Printf("Hello world")`.
3. `_` operator.
This is the operator that is difficult to understand without someone explaining it to you.
```Go
import (
"database/sql"
_ "github.com/ziutek/mymysql/godrv"
)
```
The `_` operator actually means we just want to import that package and execute its `init` function, and we are not sure if we want to use the functions belonging to that package.
## Links

View File

@@ -3,12 +3,12 @@
## struct
We can define new types of containers of other properties or fields in Go just like in other programming languages. For example, we can create a type called `person` to represent a person, with fields name and age. We call this kind of type a `struct`.
type person struct {
name string
age int
}
```Go
type person struct {
name string
age int
}
```
Look how easy it is to define a `struct`!
There are two fields.
@@ -17,75 +17,77 @@ There are two fields.
- `age` is a `int` used to store a person's age.
Let's see how to use it.
```Go
type person struct {
name string
age int
}
type person struct {
name string
age int
}
var P person // p is person type
P.name = "Astaxie" // assign "Astaxie" to the field 'name' of p
P.age = 25 // assign 25 to field 'age' of p
fmt.Printf("The person's name is %s\n", P.name) // access field 'name' of p
var P person // p is person type
P.name = "Astaxie" // assign "Astaxie" to the field 'name' of p
P.age = 25 // assign 25 to field 'age' of p
fmt.Printf("The person's name is %s\n", P.name) // access field 'name' of p
```
There are three more ways to define a struct.
- Assign initial values by order
P := person{"Tom", 25}
```Go
P := person{"Tom", 25}
```
- Use the format `field:value` to initialize the struct without order
P := person{age:24, name:"Bob"}
```Go
P := person{age:24, name:"Bob"}
```
- Define an anonymous struct, then initialize it
P := struct{name string; age int}{"Amy",18}
```Go
P := struct{name string; age int}{"Amy",18}
```
Let's see a complete example.
```Go
package main
package main
import "fmt"
import "fmt"
// define a new type
type person struct {
name string
age int
// define a new type
type person struct {
name string
age int
}
// compare the age of two people, then return the older person and differences of age
// struct is passed by value
func Older(p1, p2 person) (person, int) {
if p1.age > p2.age {
return p1, p1.age - p2.age
}
return p2, p2.age - p1.age
}
// compare the age of two people, then return the older person and differences of age
// struct is passed by value
func Older(p1, p2 person) (person, int) {
if p1.age>p2.age {
return p1, p1.age-p2.age
}
return p2, p2.age-p1.age
}
func main() {
var tom person
func main() {
var tom person
// initialization
tom.name, tom.age = "Tom", 18
// initialization
tom.name, tom.age = "Tom", 18
// initialize two values by format "field:value"
bob := person{age: 25, name: "Bob"}
// initialize two values by format "field:value"
bob := person{age:25, name:"Bob"}
// initialize two values with order
paul := person{"Paul", 43}
// initialize two values with order
paul := person{"Paul", 43}
tb_Older, tb_diff := Older(tom, bob)
tp_Older, tp_diff := Older(tom, paul)
bp_Older, bp_diff := Older(bob, paul)
tb_Older, tb_diff := Older(tom, bob)
tp_Older, tp_diff := Older(tom, paul)
bp_Older, bp_diff := Older(bob, paul)
fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, bob.name, tb_Older.name, tb_diff)
fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, bob.name, tb_Older.name, tb_diff)
fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, paul.name, tp_Older.name, tp_diff)
fmt.Printf("Of %s and %s, %s is older by %d years\n", tom.name, paul.name, tp_Older.name, tp_diff)
fmt.Printf("Of %s and %s, %s is older by %d years\n", bob.name, paul.name, bp_Older.name, bp_diff)
}
fmt.Printf("Of %s and %s, %s is older by %d years\n", bob.name, paul.name, bp_Older.name, bp_diff)
}
```
### embedded fields in struct
I've just introduced to you how to define a struct with field names and type. In fact, Go supports fields without names, but with types. We call these embedded fields.
@@ -93,120 +95,126 @@ I've just introduced to you how to define a struct with field names and type. In
When the embedded field is a struct, all the fields in that struct will implicitly be the fields in the struct in which it has been embdedded.
Let's see one example.
```Go
package main
package main
import "fmt"
import "fmt"
type Human struct {
name string
age int
weight int
}
type Human struct {
name string
age int
weight int
}
type Student struct {
Human // embedded field, it means Student struct includes all fields that Human has.
specialty string
}
type Student struct {
Human // embedded field, it means Student struct includes all fields that Human has.
specialty string
}
func main() {
// initialize a student
mark := Student{Human{"Mark", 25, 120}, "Computer Science"}
func main() {
// initialize a student
mark := Student{Human{"Mark", 25, 120}, "Computer Science"}
// access fields
fmt.Println("His name is ", mark.name)
fmt.Println("His age is ", mark.age)
fmt.Println("His weight is ", mark.weight)
fmt.Println("His specialty is ", mark.specialty)
// modify notes
mark.specialty = "AI"
fmt.Println("Mark changed his specialty")
fmt.Println("His specialty is ", mark.specialty)
// modify age
fmt.Println("Mark become old")
mark.age = 46
fmt.Println("His age is", mark.age)
// modify weight
fmt.Println("Mark is not an athlet anymore")
mark.weight += 60
fmt.Println("His weight is", mark.weight)
}
// access fields
fmt.Println("His name is ", mark.name)
fmt.Println("His age is ", mark.age)
fmt.Println("His weight is ", mark.weight)
fmt.Println("His specialty is ", mark.specialty)
// modify notes
mark.specialty = "AI"
fmt.Println("Mark changed his specialty")
fmt.Println("His specialty is ", mark.specialty)
// modify age
fmt.Println("Mark become old")
mark.age = 46
fmt.Println("His age is", mark.age)
// modify weight
fmt.Println("Mark is not an athlet anymore")
mark.weight += 60
fmt.Println("His weight is", mark.weight)
}
```
![](images/2.4.student_struct.png?raw=true)
Figure 2.7 Embedding in Student and Human
We see that we can access the `age` and `name` fields in Student just like we can in Human. This is how embedded fields work. It's very cool, isn't it? Hold on, there's something cooler! You can even use Student to access Human in this embedded field!
```Go
mark.Human = Human{"Marcus", 55, 220}
mark.Human.age -= 1
```
All the types in Go can be used as embedded fields.
```Go
package main
package main
import "fmt"
import "fmt"
type Skills []string
type Skills []string
type Human struct {
name string
age int
weight int
}
type Human struct {
name string
age int
weight int
}
type Student struct {
Human // struct as embedded field
Skills // string slice as embedded field
int // built-in type as embedded field
specialty string
}
type Student struct {
Human // struct as embedded field
Skills // string slice as embedded field
int // built-in type as embedded field
specialty string
}
func main() {
// initialize Student Jane
jane := Student{Human:Human{"Jane", 35, 100}, specialty:"Biology"}
// access fields
fmt.Println("Her name is ", jane.name)
fmt.Println("Her age is ", jane.age)
fmt.Println("Her weight is ", jane.weight)
fmt.Println("Her specialty is ", jane.specialty)
// modify value of skill field
jane.Skills = []string{"anatomy"}
fmt.Println("Her skills are ", jane.Skills)
fmt.Println("She acquired two new ones ")
jane.Skills = append(jane.Skills, "physics", "golang")
fmt.Println("Her skills now are ", jane.Skills)
// modify embedded field
jane.int = 3
fmt.Println("Her preferred number is ", jane.int)
}
func main() {
// initialize Student Jane
jane := Student{Human: Human{"Jane", 35, 100}, specialty: "Biology"}
// access fields
fmt.Println("Her name is ", jane.name)
fmt.Println("Her age is ", jane.age)
fmt.Println("Her weight is ", jane.weight)
fmt.Println("Her specialty is ", jane.specialty)
// modify value of skill field
jane.Skills = []string{"anatomy"}
fmt.Println("Her skills are ", jane.Skills)
fmt.Println("She acquired two new ones ")
jane.Skills = append(jane.Skills, "physics", "golang")
fmt.Println("Her skills now are ", jane.Skills)
// modify embedded field
jane.int = 3
fmt.Println("Her preferred number is ", jane.int)
}
```
In the above example, we can see that all types can be embedded fields and we can use functions to operate on them.
There is one more problem however. If Human has a field called `phone` and Student has a field with same name, what should we do?
Go use a very simple way to solve it. The outer fields get upper access levels, which means when you access `student.phone`, we will get the field called phone in student, not the one in the Human struct. This feature can be simply seen as field `overload`ing.
```Go
package main
package main
import "fmt"
import "fmt"
type Human struct {
name string
age int
phone string // Human has phone field
}
type Human struct {
name string
age int
phone string // Human has phone field
}
type Employee struct {
Human // embedded field Human
specialty string
phone string // phone in employee
}
type Employee struct {
Human // embedded field Human
specialty string
phone string // phone in employee
}
func main() {
Bob := Employee{Human{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"}
fmt.Println("Bob's work phone is:", Bob.phone)
// access phone field in Human
fmt.Println("Bob's personal phone is:", Bob.Human.phone)
}
func main() {
Bob := Employee{Human{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"}
fmt.Println("Bob's work phone is:", Bob.phone)
// access phone field in Human
fmt.Println("Bob's personal phone is:", Bob.Human.phone)
}
```
## Links
- [Directory](preface.md)

View File

@@ -5,25 +5,27 @@ We talked about functions and structs in the last two sections, but did you ever
## method
Suppose you define a "rectangle" struct and you want to calculate its area. We'd typically use the following code to achieve this goal.
```Go
package main
package main
import "fmt"
import "fmt"
type Rectangle struct {
width, height float64
}
type Rectangle struct {
width, height float64
}
func area(r Rectangle) float64 {
return r.width*r.height
}
func area(r Rectangle) float64 {
return r.width * r.height
}
func main() {
r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4}
fmt.Println("Area of r1 is: ", area(r1))
fmt.Println("Area of r2 is: ", area(r2))
}
func main() {
r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4}
fmt.Println("Area of r1 is: ", area(r1))
fmt.Println("Area of r2 is: ", area(r2))
}
```
The above example can calculate a rectangle's area. We use the function called `area`, but it's not a method of the rectangle struct (like class methods in classic object-oriented languages). The function and struct are two independent things as you may notice.
It's not a problem so far. However, if you also have to calculate the area of a circle, square, pentagon, or any other kind of shape, you are going to need to add additional functions with very similar names.
@@ -43,45 +45,47 @@ As Rob Pike said.
"A method is a function with an implicit first argument, called a receiver."
Syntax of method.
func (r ReceiverType) funcName(parameters) (results)
```Go
func (r ReceiverType) funcName(parameters) (results)
```
Let's change our example using `method` instead.
```Go
package main
package main
import (
"fmt"
"math"
)
import (
"fmt"
"math"
)
type Rectangle struct {
width, height float64
}
type Rectangle struct {
width, height float64
}
type Circle struct {
radius float64
}
type Circle struct {
radius float64
}
func (r Rectangle) area() float64 {
return r.width*r.height
}
func (r Rectangle) area() float64 {
return r.width * r.height
}
func (c Circle) area() float64 {
return c.radius * c.radius * math.Pi
}
func (c Circle) area() float64 {
return c.radius * c.radius * math.Pi
}
func main() {
r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4}
c1 := Circle{10}
c2 := Circle{25}
func main() {
r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4}
c1 := Circle{10}
c2 := Circle{25}
fmt.Println("Area of r1 is: ", r1.area())
fmt.Println("Area of r2 is: ", r2.area())
fmt.Println("Area of c1 is: ", c1.area())
fmt.Println("Area of c2 is: ", c2.area())
}
fmt.Println("Area of r1 is: ", r1.area())
fmt.Println("Area of r2 is: ", r2.area())
fmt.Println("Area of c1 is: ", c1.area())
fmt.Println("Area of c2 is: ", c2.area())
}
```
Notes for using methods.
- If the name of methods are the same but they don't share the same receivers, they are not the same.
@@ -99,103 +103,105 @@ One thing that's worth noting is that the method with a dotted line means the re
Can the receiver only be a struct? Of course not. Any type can be the receiver of a method. You may be confused about customized types. Struct is a special kind of customized type -there are more customized types.
Use the following format to define a customized type.
type typeName typeLiteral
```Go
type typeName typeLiteral
```
Examples of customized types:
```Go
type ages int
type ages int
type money float32
type money float32
type months map[string]int
type months map[string]int
m := months {
"January":31,
"February":28,
...
"December":31,
}
m := months {
"January":31,
"February":28,
...
"December":31,
}
```
I hope that you know how to use customized types now. Similar to `typedef` in C, we use `ages` to substitute `int` in the above example.
Let's get back to talking about `method`.
You can use as many methods in custom types as you want.
```Go
package main
package main
import "fmt"
import "fmt"
const(
WHITE = iota
BLACK
BLUE
RED
YELLOW
)
const (
WHITE = iota
BLACK
BLUE
RED
YELLOW
)
type Color byte
type Color byte
type Box struct {
width, height, depth float64
color Color
type Box struct {
width, height, depth float64
color Color
}
type BoxList []Box //a slice of boxes
func (b Box) Volume() float64 {
return b.width * b.height * b.depth
}
func (b *Box) SetColor(c Color) {
b.color = c
}
func (bl BoxList) BiggestsColor() Color {
v := 0.00
k := Color(WHITE)
for _, b := range bl {
if b.Volume() > v {
v = b.Volume()
k = b.color
}
}
return k
}
func (bl BoxList) PaintItBlack() {
for i, _ := range bl {
bl[i].SetColor(BLACK)
}
}
func (c Color) String() string {
strings := []string{"WHITE", "BLACK", "BLUE", "RED", "YELLOW"}
return strings[c]
}
func main() {
boxes := BoxList{
Box{4, 4, 4, RED},
Box{10, 10, 1, YELLOW},
Box{1, 1, 20, BLACK},
Box{10, 10, 1, BLUE},
Box{10, 30, 1, WHITE},
Box{20, 20, 20, YELLOW},
}
type BoxList []Box //a slice of boxes
fmt.Printf("We have %d boxes in our set\n", len(boxes))
fmt.Println("The volume of the first one is", boxes[0].Volume(), "cm³")
fmt.Println("The color of the last one is", boxes[len(boxes)-1].color.String())
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
func (b Box) Volume() float64 {
return b.width * b.height * b.depth
}
fmt.Println("Let's paint them all black")
boxes.PaintItBlack()
fmt.Println("The color of the second one is", boxes[1].color.String())
func (b *Box) SetColor(c Color) {
b.color = c
}
fmt.Println("Obviously, now, the biggest one is", boxes.BiggestsColor().String())
}
func (bl BoxList) BiggestsColor() Color {
v := 0.00
k := Color(WHITE)
for _, b := range bl {
if b.Volume() > v {
v = b.Volume()
k = b.color
}
}
return k
}
func (bl BoxList) PaintItBlack() {
for i, _ := range bl {
bl[i].SetColor(BLACK)
}
}
func (c Color) String() string {
strings := []string {"WHITE", "BLACK", "BLUE", "RED", "YELLOW"}
return strings[c]
}
func main() {
boxes := BoxList {
Box{4, 4, 4, RED},
Box{10, 10, 1, YELLOW},
Box{1, 1, 20, BLACK},
Box{10, 10, 1, BLUE},
Box{10, 30, 1, WHITE},
Box{20, 20, 20, YELLOW},
}
fmt.Printf("We have %d boxes in our set\n", len(boxes))
fmt.Println("The volume of the first one is", boxes[0].Volume(), "cm³")
fmt.Println("The color of the last one is",boxes[len(boxes)-1].color.String())
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
fmt.Println("Let's paint them all black")
boxes.PaintItBlack()
fmt.Println("The color of the second one is", boxes[1].color.String())
fmt.Println("Obviously, now, the biggest one is", boxes.BiggestsColor().String())
}
```
We define some constants and customized types.
- Use `Color` as alias of `byte`.
@@ -225,79 +231,83 @@ You may also be asking whether we should use `(&bl[i]).SetColor(BLACK)` in `Pain
### Inheritance of method
We learned about inheritance of fields in the last section. Similarly, we also have method inheritance in Go. If an anonymous field has methods, then the struct that contains the field will have all the methods from it as well.
```Go
package main
package main
import "fmt"
import "fmt"
type Human struct {
name string
age int
phone string
}
type Human struct {
name string
age int
phone string
}
type Student struct {
Human // anonymous field
school string
}
type Student struct {
Human // anonymous field
school string
}
type Employee struct {
Human
company string
}
type Employee struct {
Human
company string
}
// define a method in Human
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
// define a method in Human
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
mark.SayHi()
sam.SayHi()
}
mark.SayHi()
sam.SayHi()
}
```
### Method overload
If we want Employee to have its own method `SayHi`, we can define a method that has the same name in Employee, and it will hide `SayHi` in Human when we call it.
```Go
package main
package main
import "fmt"
import "fmt"
type Human struct {
name string
age int
phone string
}
type Human struct {
name string
age int
phone string
}
type Student struct {
Human
school string
}
type Student struct {
Human
school string
}
type Employee struct {
Human
company string
}
type Employee struct {
Human
company string
}
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func (e *Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //Yes you can split into 2 lines here.
}
func (e *Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //Yes you can split into 2 lines here.
}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
mark.SayHi()
sam.SayHi()
}
mark.SayHi()
sam.SayHi()
}
```
You are able to write an Object-oriented program now, and methods use rule of capital letter to decide whether public or private as well.
## Links

View File

@@ -19,70 +19,72 @@ This combination of methods is called an interface and is implemented by both St
### Type of Interface
An interface defines a set of methods, so if a type implements all the methods we say that it implements the interface.
```Go
type Human struct {
name string
age int
phone string
}
type Human struct {
name string
age int
phone string
}
type Student struct {
Human
school string
loan float32
}
type Student struct {
Human
school string
loan float32
}
type Employee struct {
Human
company string
money float32
}
type Employee struct {
Human
company string
money float32
}
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func (h *Human) Sing(lyrics string) {
fmt.Println("La la, la la la, la la la la la...", lyrics)
}
func (h *Human) Sing(lyrics string) {
fmt.Println("La la, la la la, la la la la la...", lyrics)
}
func (h *Human) Guzzle(beerStein string) {
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}
func (h *Human) Guzzle(beerStein string) {
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}
// Employee overloads Sayhi
func (e *Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //Yes you can split into 2 lines here.
}
// Employee overloads Sayhi
func (e *Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //Yes you can split into 2 lines here.
}
func (s *Student) BorrowMoney(amount float32) {
s.loan += amount // (again and again and...)
}
func (s *Student) BorrowMoney(amount float32) {
s.loan += amount // (again and again and...)
}
func (e *Employee) SpendSalary(amount float32) {
e.money -= amount // More vodka please!!! Get me through the day!
}
func (e *Employee) SpendSalary(amount float32) {
e.money -= amount // More vodka please!!! Get me through the day!
}
// define interface
type Men interface {
SayHi()
Sing(lyrics string)
Guzzle(beerStein string)
}
// define interface
type Men interface {
SayHi()
Sing(lyrics string)
Guzzle(beerStein string)
}
type YoungChap interface {
SayHi()
Sing(song string)
BorrowMoney(amount float32)
}
type YoungChap interface {
SayHi()
Sing(song string)
BorrowMoney(amount float32)
}
type ElderlyGent interface {
SayHi()
Sing(song string)
SpendSalary(amount float32)
}
type ElderlyGent interface {
SayHi()
Sing(song string)
SpendSalary(amount float32)
}
```
We know that an interface can be implemented by any type, and one type can implement many interfaces simultaneously.
Note that any type implements the empty interface `interface{}` because it doesn't have any methods and all types have zero methods by default.
@@ -92,87 +94,87 @@ Note that any type implements the empty interface `interface{}` because it doesn
So what kind of values can be put in the interface? If we define a variable as a type interface, any type that implements the interface can assigned to this variable.
Like the above example, if we define a variable "m" as interface Men, then any one of Student, Human or Employee can be assigned to "m". So we could have a slice of Men, and any type that implements interface Men can assign to this slice. Be aware however that the slice of interface doesn't have the same behavior as a slice of other types.
```Go
package main
package main
import "fmt"
type Human struct {
name string
age int
phone string
}
type Student struct {
Human
school string
loan float32
}
type Employee struct {
Human
company string
money float32
}
func (h Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func (h Human) Sing(lyrics string) {
fmt.Println("La la la la...", lyrics)
}
func (e Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //Yes you can split into 2 lines here.
}
// Interface Men implemented by Human, Student and Employee
type Men interface {
SayHi()
Sing(lyrics string)
}
func main() {
mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
tom := Employee{Human{"Sam", 36, "444-222-XXX"}, "Things Ltd.", 5000}
// define interface i
var i Men
//i can store Student
i = mike
fmt.Println("This is Mike, a Student:")
i.SayHi()
i.Sing("November rain")
//i can store Employee
i = tom
fmt.Println("This is Tom, an Employee:")
i.SayHi()
i.Sing("Born to be wild")
// slice of Men
fmt.Println("Let's use a slice of Men and see what happens")
x := make([]Men, 3)
// these three elements are different types but they all implemented interface Men
x[0], x[1], x[2] = paul, sam, mike
for _, value := range x {
value.SayHi()
}
}
import "fmt"
type Human struct {
name string
age int
phone string
}
type Student struct {
Human
school string
loan float32
}
type Employee struct {
Human
company string
money float32
}
func (h Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
func (h Human) Sing(lyrics string) {
fmt.Println("La la la la...", lyrics)
}
func (e Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //Yes you can split into 2 lines here.
}
// Interface Men implemented by Human, Student and Employee
type Men interface {
SayHi()
Sing(lyrics string)
}
func main() {
mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
tom := Employee{Human{"Sam", 36, "444-222-XXX"}, "Things Ltd.", 5000}
// define interface i
var i Men
//i can store Student
i = mike
fmt.Println("This is Mike, a Student:")
i.SayHi()
i.Sing("November rain")
//i can store Employee
i = tom
fmt.Println("This is Tom, an Employee:")
i.SayHi()
i.Sing("Born to be wild")
// slice of Men
fmt.Println("Let's use a slice of Men and see what happens")
x := make([]Men, 3)
// these three elements are different types but they all implemented interface Men
x[0], x[1], x[2] = paul, sam, mike
for _, value := range x {
value.SayHi()
}
}
```
An interface is a set of abstract methods, and can be implemented by non-interface types. It cannot therefore implement itself.
### Empty interface
An empty interface is an interface that doesn't contain any methods, so all types implement an empty interface. This fact is very useful when we want to store all types at some point, and is similar to void* in C.
```Go
// define a as empty interface
var a interface{}
var i int = 5
@@ -180,7 +182,7 @@ An empty interface is an interface that doesn't contain any methods, so all type
// a can store value of any type
a = i
a = s
```
If a function uses an empty interface as its argument type, it can accept any type; if a function uses empty interface as its return value type, it can return any type.
### Method arguments of an interface
@@ -188,42 +190,42 @@ If a function uses an empty interface as its argument type, it can accept any ty
Any variable can be used in an interface. So how can we use this feature to pass any type of variable to a function?
For example we use fmt.Println a lot, but have you ever noticed that it can accept any type of argument? Looking at the open source code of fmt, we see the following definition.
type Stringer interface {
String() string
}
```Go
type Stringer interface {
String() string
}
```
This means any type that implements interface Stringer can be passed to fmt.Println as an argument. Let's prove it.
```Go
package main
package main
import (
"fmt"
"strconv"
)
import (
"fmt"
"strconv"
)
type Human struct {
name string
age int
phone string
}
type Human struct {
name string
age int
phone string
}
// Human implemented fmt.Stringer
func (h Human) String() string {
return "Name:" + h.name + ", Age:" + strconv.Itoa(h.age) + " years, Contact:" + h.phone
}
// Human implemented fmt.Stringer
func (h Human) String() string {
return "Name:" + h.name + ", Age:" + strconv.Itoa(h.age) + " years, Contact:" + h.phone
}
func main() {
Bob := Human{"Bob", 39, "000-7777-XXX"}
fmt.Println("This Human is : ", Bob)
}
func main() {
Bob := Human{"Bob", 39, "000-7777-XXX"}
fmt.Println("This Human is : ", Bob)
}
```
Looking back to the example of Box, you will find that Color implements interface Stringer as well, so we are able to customize the print format. If we don't implement this interface, fmt.Println prints the type with its default format.
```Go
fmt.Println("The biggest one is", boxes.BiggestsColor().String())
fmt.Println("The biggest one is", boxes.BiggestsColor())
```
Attention: If the type implemented the interface `error`, fmt will call `error()`, so you don't have to implement Stringer at this point.
### Type of variable in an interface
@@ -237,90 +239,92 @@ Go has the syntax `value, ok := element.(T)`. This checks to see if the variable
If the element is the type that we expect, ok will be true, false otherwise.
Let's use an example to see more clearly.
```Go
package main
package main
import (
"fmt"
"strconv"
)
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
}
func main() {
list := make(List, 3)
list[0] = 1 // an int
list[1] = "Hello" // a string
list[2] = Person{"Dennis", 70}
for index, element := range list {
if value, ok := element.(int); ok {
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
} else if value, ok := element.(string); ok {
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
} else if value, ok := element.(Person); ok {
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
} else {
fmt.Printf("list[%d] is of a different type\n", index)
}
import (
"fmt"
"strconv"
)
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
}
func main() {
list := make(List, 3)
list[0] = 1 // an int
list[1] = "Hello" // a string
list[2] = Person{"Dennis", 70}
for index, element := range list {
if value, ok := element.(int); ok {
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
} else if value, ok := element.(string); ok {
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
} else if value, ok := element.(Person); ok {
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
} else {
fmt.Printf("list[%d] is of a different type\n", index)
}
}
}
```
It's quite easy to use this pattern, but if we have many types to test, we'd better use `switch`.
- switch test
Let's use `switch` to rewrite the above example.
package main
import (
"fmt"
"strconv"
)
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
}
func main() {
list := make(List, 3)
list[0] = 1 //an int
list[1] = "Hello" //a string
list[2] = Person{"Dennis", 70}
for index, element := range list {
switch value := element.(type) {
case int:
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
case string:
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
case Person:
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
default:
fmt.Println("list[%d] is of a different type", index)
}
```Go
package main
import (
"fmt"
"strconv"
)
type Element interface{}
type List []Element
type Person struct {
name string
age int
}
func (p Person) String() string {
return "(name: " + p.name + " - age: " + strconv.Itoa(p.age) + " years)"
}
func main() {
list := make(List, 3)
list[0] = 1 //an int
list[1] = "Hello" //a string
list[2] = Person{"Dennis", 70}
for index, element := range list {
switch value := element.(type) {
case int:
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
case string:
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
case Person:
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
default:
fmt.Println("list[%d] is of a different type", index)
}
}
}
```
One thing you should remember is that `element.(type)` cannot be used outside of the `switch` body, which means in that case you have to use the `comma-ok` pattern .
@@ -329,63 +333,63 @@ One thing you should remember is that `element.(type)` cannot be used outside of
The most beautiful thing is that Go has a lot of built-in logic syntax, such as anonymous fields in struct. Not suprisingly, we can use interfaces as anonymous fields as well, but we call them `Embedded interfaces`. Here, we follow the same rules as anonymous fields. More specifically, if an interface has another interface embedded within it, it will behave as if it has all the methods that the embedded interface has.
We can see that the source file in `container/heap` has the following definition:
type Interface interface {
sort.Interface // embedded sort.Interface
Push(x interface{}) //a Push method to push elements into the heap
Pop() interface{} //a Pop method that pops elements from the heap
}
```Go
type Interface interface {
sort.Interface // embedded sort.Interface
Push(x interface{}) //a Push method to push elements into the heap
Pop() interface{} //a Pop method that pops elements from the heap
}
```
We see that `sort.Interface` is an embedded interface, so the above Interface has the three methods contained within the `sort.Interface` implicitly.
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less returns whether the element with index i should sort
// before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
```Go
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less returns whether the element with index i should sort
// before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
```
Another example is the `io.ReadWriter` in package `io`.
// io.ReadWriter
type ReadWriter interface {
Reader
Writer
}
```Go
// io.ReadWriter
type ReadWriter interface {
Reader
Writer
}
```
### Reflection
Reflection in Go is used for determining information at runtime. We use the `reflect` package, and this official [article](http://golang.org/doc/articles/laws_of_reflection.html) explains how reflect works in Go.
There are three steps involved when using reflect. First, we need to convert an interface to reflect types (reflect.Type or reflect.Value, this depends on the situation).
```Go
t := reflect.TypeOf(i) // get meta-data in type i, and use t to get all elements
v := reflect.ValueOf(i) // get actual value in type i, and use v to change its value
```
After that, we can convert the reflected types to get the values that we need.
```Go
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println("type:", v.Type())
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
fmt.Println("value:", v.Float())
```
Finally, if we want to change the values of the reflected types, we need to make it modifiable. As discussed earlier, there is a difference between pass by value and pass by reference. The following code will not compile.
```Go
var x float64 = 3.4
v := reflect.ValueOf(x)
v.SetFloat(7.1)
```
Instead, we must use the following code to change the values from reflect types.
```Go
var x float64 = 3.4
p := reflect.ValueOf(&x)
v := p.Elem()
v.SetFloat(7.1)
```
We have just discussed the basics of reflection, however you must practice more in order to understand more.
## Links

View File

@@ -7,32 +7,33 @@ It is said that Go is the C language of the 21st century. I think there are two
goroutines and concurrency are built into the core design of Go. They're similar to threads but work differently. More than a dozen goroutines maybe only have 5 or 6 underlying threads. Go also gives you full support to sharing memory in your goroutines. One goroutine usually uses 4~5 KB of stack memory. Therefore, it's not hard to run thousands of goroutines on a single computer. A goroutine is more lightweight, more efficient and more convenient than system threads.
goroutines run on the thread manager at runtime in Go. We use the `go` keyword to create a new goroutine, which is a function at the underlying level ( ***main() is a goroutine*** ).
```Go
go hello(a, b, c)
```
Let's see an example.
```Go
package main
package main
import (
"fmt"
"runtime"
)
import (
"fmt"
"runtime"
)
func say(s string) {
for i := 0; i < 5; i++ {
runtime.Gosched()
fmt.Println(s)
}
func say(s string) {
for i := 0; i < 5; i++ {
runtime.Gosched()
fmt.Println(s)
}
}
func main() {
go say("world") // create a new goroutine
say("hello") // current goroutine
}
func main() {
go say("world") // create a new goroutine
say("hello") // current goroutine
}
```
Output
```
hello
world
hello
@@ -42,7 +43,7 @@ Output
hello
world
hello
```
We see that it's very easy to use concurrency in Go by using the keyword `go`. In the above example, these two goroutines share some memory, but we would better off following the design recipe: Don't use shared data to communicate, use communication to share data.
runtime.Gosched() means let the CPU execute other goroutines, and come back at some point.
@@ -54,93 +55,96 @@ Before Go 1.5,The scheduler only uses one thread to run all goroutines, which me
## channels
goroutines run in the same memory address space, so you have to maintain synchronization when you want to access shared memory. How do you communicate between different goroutines? Go uses a very good communication mechanism called `channel`. `channel` is like a two-way pipeline in Unix shells: use `channel` to send or receive data. The only data type that can be used in channels is the type `channel` and the keyword `chan`. Be aware that you have to use `make` to create a new `channel`.
```Go
ci := make(chan int)
cs := make(chan string)
cf := make(chan interface{})
```
channel uses the operator `<-` to send or receive data.
```Go`
ch <- v // send v to channel ch.
v := <-ch // receive data from ch, and assign to v
```
Let's see more examples.
```Go
package main
package main
import "fmt"
import "fmt"
func sum(a []int, c chan int) {
total := 0
for _, v := range a {
total += v
}
c <- total // send total to c
func sum(a []int, c chan int) {
total := 0
for _, v := range a {
total += v
}
c <- total // send total to c
}
func main() {
a := []int{7, 2, 8, -9, 4, 0}
func main() {
a := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
x, y := <-c, <-c // receive from c
c := make(chan int)
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x + y)
}
fmt.Println(x, y, x+y)
}
```
Sending and receiving data in channels blocks by default, so it's much easier to use synchronous goroutines. What I mean by block is that a goroutine will not continue when receiving data from an empty channel, i.e (`value := <-ch`), until other goroutines send data to this channel. On the other hand, the goroutine will not continue until the data it sends to a channel, i.e (`ch<-5`), is received.
## Buffered channels
I introduced non-buffered channels above. Go also has buffered channels that can store more than a single element. For example, `ch := make(chan bool, 4)`, here we create a channel that can store 4 boolean elements. So in this channel, we are able to send 4 elements into it without blocking, but the goroutine will be blocked when you try to send a fifth element and no goroutine receives it.
```Go
ch := make(chan type, n)
n == 0 ! non-bufferblock
n > 0 ! buffernon-block until n elements in the channel
```
You can try the following code on your computer and change some values.
package main
```Go
package main
import "fmt"
import "fmt"
func main() {
c := make(chan int, 2) // change 2 to 1 will have runtime error, but 3 is fine
c <- 1
c <- 2
fmt.Println(<-c)
fmt.Println(<-c)
}
func main() {
c := make(chan int, 2) // change 2 to 1 will have runtime error, but 3 is fine
c <- 1
c <- 2
fmt.Println(<-c)
fmt.Println(<-c)
}
```
## Range and Close
We can use range to operate on buffer channels as in slice and map.
```Go
package main
package main
import (
"fmt"
)
import (
"fmt"
)
func fibonacci(n int, c chan int) {
x, y := 1, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x + y
}
close(c)
func fibonacci(n int, c chan int) {
x, y := 1, 1
for i := 0; i < n; i++ {
c <- x
x, y = y, x+y
}
close(c)
}
func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
func main() {
c := make(chan int, 10)
go fibonacci(cap(c), c)
for i := range c {
fmt.Println(i)
}
}
```
`for i := range c` will not stop reading data from channel until the channel is closed. We use the keyword `close` to close the channel in above example. It's impossible to send or receive data on a closed channel; you can use `v, ok := <-ch` to test if a channel is closed. If `ok` returns false, it means the there is no data in that channel and it was closed.
Remember to always close channels in producers and not in consumers, or it's very easy to get into panic status.
@@ -152,67 +156,69 @@ Another thing you need to remember is that channels are not like files. You don'
In the above examples, we only use one channel, but how can we deal with more than one channel? Go has a keyword called `select` to listen to many channels.
`select` is blocking by default and it continues to execute only when one of channels has data to send or receive. If several channels are ready to use at the same time, select chooses which to execute randomly.
```Go
package main
package main
import "fmt"
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 1, 1
for {
select {
case c <- x:
x, y = y, x + y
case <-quit:
fmt.Println("quit")
return
}
}
func fibonacci(c, quit chan int) {
x, y := 1, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
```
`select` has a `default` case as well, just like `switch`. When all the channels are not ready for use, it executes the default case (it doesn't wait for the channel anymore).
select {
case i := <-c:
// use i
default:
// executes here when c is blocked
}
```Go
select {
case i := <-c:
// use i
default:
// executes here when c is blocked
}
```
## Timeout
Sometimes a goroutine becomes blocked. How can we avoid this to prevent the whole program from blocking? It's simple, we can set a timeout in the select.
```Go
func main() {
c := make(chan int)
o := make(chan bool)
go func() {
for {
select {
case v := <-c:
println(v)
case <-time.After(5 * time.Second):
println("timeout")
o <- true
break
}
}
}()
<-o
}
func main() {
c := make(chan int)
o := make(chan bool)
go func() {
for {
select {
case v := <- c:
println(v)
case <- time.After(5 * time.Second):
println("timeout")
o <- true
break
}
}
}()
<- o
}
```
## Runtime goroutine
The package `runtime` has some functions for dealing with goroutines.

View File

@@ -1,13 +1,13 @@
# 2.8 Summary
In this chapter, we mainly introduced the 25 Go keywords. Let's review what they are and what they do.
```Go
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
```
- `var` and `const` are used to define variables and constants.
- `package` and `import` are for package use.
- `func` is used to define functions and methods.

View File

@@ -141,8 +141,8 @@ Ubuntu是目前使用最多的Linux桌面系统使用`apt-get`命令来管理
sudo add-apt-repository ppa:gophers/go
sudo apt-get update
sudo apt-get install golang-stable git-core mercurial
````
###wget
```
### wget
```sh
wget https://storage.googleapis.com/golang/go1.8.linux-amd64.tar.gz

View File

@@ -299,7 +299,7 @@ Atom是Github基于Electron和web技术构建的开源编辑器, 是一款很漂
就会开始安装 go-plus go-plus 插件会自动安装对应的依赖插件如果没有安装对应的go的类库会自动运行: go get 安装。
##Gogland
## Gogland
Gogland是JetBrains公司推出的Go语言集成开发环境是Idea Go插件是强化版。Gogland同样基于IntelliJ平台开发支持JetBrains的插件体系。