From 5315ab318eacd118440ff7c5c50670a685d7d8bc Mon Sep 17 00:00:00 2001 From: ldynia Date: Sun, 16 Jul 2017 15:30:30 +0200 Subject: [PATCH] adding minor changes --- en/02.1.md | 20 +++++----- en/02.2.md | 90 +++++++++++++++++++++---------------------- en/02.3.md | 109 +++++++++++++++++++++++++++-------------------------- 3 files changed, 111 insertions(+), 108 deletions(-) diff --git a/en/02.1.md b/en/02.1.md index 2f584860..2123a1b0 100644 --- a/en/02.1.md +++ b/en/02.1.md @@ -6,9 +6,9 @@ The Go programming language was created with one goal in mind, to be able to bui public static void main() { } - - or - public static void main() + + or + public static void main() { } @@ -21,13 +21,13 @@ For other languages there are many variables when it comes to writing code, ever So to mitigate all the problems that Google faced with the current tools, they wrote a systems language called Go, which you are about to learn! There are many advantages to using golang, and there might be disadvantages too for every coin has both sides. But significant improvements in places like code formatting, since they designed the language in such a way that there won't be wars on how to format code, the gocode written by anyone in the world (assuming they know and use `gofmt`) will look exactly the same, this won't seem to matter until you work in a team! also when the company uses automated code review or some other fancy technique then in other languages which don't have strict and standard formatting rules then the code might get screwed up, but not in go! -Go was designed with concurrency in mind, please note that parallelism != concurrency, there is an amazing post by Rob Pike on the golang blog, blog.golang.org, you will find it there, it is worth a read. +Go was designed with concurrency in mind, please note that parallelism != concurrency, there is an amazing post by Rob Pike on the golang blog, [www.blog.golang.org](https://blog.golang.org/concurrency-is-not-parallelism), you will find it there, it is worth a read. Another very important change that go has brought in programming that I personally love is the concept of `GOPATH`, gone are the days when you had to create a folder called `code` and then create workspaces for eclipse and what not, now you have to keep one folder tree for go code and it'll be updated by the package manager automatically. Also under the code we are recommended to create folders with either a custom domain or the github domain, for example I created a task manager using golang so I created a set of folders `~/go/src/github.com/thewhitetulip/Tasks` note: In *nix systems `~` stands for home directory, which is the windows equivalent of `C:\\Users\\username` now the `~/go/` is the universe for the gocode in your machine, it is just a significant improvement over other languages so we can store the code efficiently without hassles, it might seem strange at first, but it does make a lot of sense over the ridiculous package names some other languages use like reverse domains. -note: along with src there are two folders `pkg` which is for packages and `bin` which is for binary +**Note:** Along with `src` there are two folders `pkg` which is for packages and `bin` which is for binary. This `GOPATH` advantage isn't just restricted to storing code in particular folder, but when you have created five packages for your project then you don't have to import them like `"import ./db"`, you can give it `import "github.com/thewhitetulip/Tasks/db"`, so while doing a `go get` on my repo, the `go` tool will find the package from `github.com/...` path if it wasn't downloaded initially, it just standardizes a lot of screwed up things in the programming discipline. @@ -44,17 +44,17 @@ According to international practice, before you learn how to program in some lan Are you ready? Let's Go! ```Go package main - + import "fmt" - + func main() { fmt.Printf("Hello, world or 你好,世界 or καλημ ́ρα κóσμ or こんにちは世界\n") } -``` +``` It prints following information. Hello, world or 你好,世界 or καλημ ́ρα κóσμ or こんにちは世界 - + ## Explanation One thing that you should know in the first is that Go programs are composed by `package`. @@ -75,7 +75,7 @@ On the sixth line, we called the function `Printf` which is from the package `fm As we mentioned in chapter 1, the package's name and the name of the folder that contains that package can be different. Here the `` comes from the name in `package `, not the folder's name. -You may notice that the example above contains many non-ASCII characters. The purpose of showing this is to tell you that Go supports UTF-8 by default. You can use any UTF-8 character in your programs. +You may notice that the example above contains many non-ASCII characters. The purpose of showing this is to tell you that Go supports UTF-8 by default. You can use any UTF-8 character in your programs. Each go file is in some package, and that package should be a distinct folder in the GOPATH, but main is a special package which doesn't require a `main` folder. This is one aspect which they left out for standardization! But should you choose to make a main folder then you have to ensure that you run the binary properly. Also one go code can't have more than one `main` go file. diff --git a/en/02.2.md b/en/02.2.md index b69cc589..c34bff2f 100644 --- a/en/02.2.md +++ b/en/02.2.md @@ -15,12 +15,12 @@ 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 /* @@ -28,9 +28,9 @@ Define multiple variables with initial 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, +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 /* @@ -38,7 +38,7 @@ so the code will look like this instead: 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 /* @@ -46,13 +46,13 @@ Well, I know this is still not simple enough for you. Let's see how we fix it. 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. +``` +Now it looks much better. Use `:=` to replace `var` and `type`, this is called a **short assignment**. It has one limitation: this form can only be used inside of a 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 @@ -60,7 +60,7 @@ 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. @@ -68,7 +68,7 @@ So-called constants are the values that are determined during compile time and y Define constants as follows. ```Go const constantName = value -// you can assign type of constants if it's necessary +// you can assign type of constants if it's necessary const Pi float32 = 3.1415926 ``` More examples. @@ -77,7 +77,7 @@ const Pi = 3.1415926 const i = 10000 const MaxThread = 10 const prefix = "astaxie_" -``` +``` ## Elementary types ### Boolean @@ -93,7 +93,7 @@ func test() { 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`. @@ -115,7 +115,7 @@ That's all? No! Go supports complex numbers as well. `complex128` (with a 64-bit 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 ``` `` ```. @@ -133,7 +133,7 @@ It's impossible to change string values by index. You will get errors when you c ```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" @@ -141,20 +141,20 @@ 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 @@ -170,7 +170,7 @@ 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. @@ -197,7 +197,7 @@ const prefix = "Go_" var i int var pi float32 var prefix string -``` +``` Group form. ```Go import( @@ -216,7 +216,7 @@ var( 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 @@ -227,13 +227,13 @@ const( x = iota // x == 0 y = iota // y == 1 z = iota // z == 2 - w // If there is no expression after the constants name, it uses the last expression, + w // If there is no expression after the constants name, it uses the last expression, //so it's saying w = iota implicitly. Therefore w == 3, and y and z both can omit "= iota" as well. ) const v = iota // once iota meets keyword `const`, it resets to `0`, so v = 0. -const ( +const ( e, f, g = iota, iota, iota // e=0,f=0,g=0 values of iota are same in one line. ) ``` @@ -251,7 +251,7 @@ The reason that Go is concise because it has some default behaviors. `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 @@ -259,17 +259,17 @@ arr[0] = 42 // array is 0-based arr[1] = 13 // assign value to element fmt.Printf("The first element is %d\n", arr[0]) // get element value, it returns 42 -fmt.Printf("The last element is %d\n", arr[9]) +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} -// define a int array with 10 elements, of which the first three are assigned. +b := [10]int{1, 2, 3} +// define a int array with 10 elements, of which the first three are assigned. //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. @@ -281,7 +281,7 @@ 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) @@ -300,8 +300,8 @@ 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 +``` +`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 @@ -318,8 +318,8 @@ a = ar[2:5] // '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 +``` +Notice the differences between `slice` and `array` when you define them. We use `[…]` to let Go calculate length but use `[]` to define slice only. Their underlying data structure. @@ -353,8 +353,8 @@ bSlice = aSlice[:3] // bSlice contains aSlice[0], aSlice[1], aSlice[2], so it h 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`, +`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. `slice` is like a struct by definition and it contains 3 parts. @@ -379,8 +379,8 @@ There are some built-in functions for slice. - `append` appends one or more elements to `slice`, and returns `slice` . - `copy` copies elements from one slice to the other, and returns the number of elements that were copied. -Attention: `append` will change the array that `slice` points to, and affect other slices that point to the same array. -Also, if there is not enough length for the slice (`(cap-len) == 0`), `append` returns a new array for this slice. When +Attention: `append` will change the array that `slice` points to, and affect other slices that point to the same array. +Also, if there is not enough length for the slice (`(cap-len) == 0`), `append` returns a new array for this slice. When this happens, other slices pointing to the old array will not be affected. ### map @@ -388,7 +388,7 @@ this happens, other slices pointing to the old array will not be affected. `map` behaves like a dictionary in Python. Use the form `map[keyType]valueType` to define it. 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 +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. @@ -396,7 +396,7 @@ var numbers map[string] int // another way to define map numbers := make(map[string]int) numbers["one"] = 1 // assign value by key -numbers["ten"] = 10 +numbers["ten"] = 10 numbers["three"] = 3 fmt.Println("The third number is: ", numbers["three"]) // get values @@ -415,7 +415,7 @@ 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 +// map has two return values. For the second return value, if the key doesn't //exist,'ok' returns false. It returns true otherwise. csharpRating, ok := rating["C#"] if ok { @@ -426,25 +426,25 @@ if ok { 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, +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' +`make` does memory allocation for built-in models, such as `map`, `slice`, and `channel`, while `new` is for types' memory allocation. -`new(T)` allocates zero-value to type `T`'s memory, returns its memory address, which is the value of type `*T`. By Go's +`new(T)` allocates zero-value to type `T`'s memory, returns its memory address, which is the value of type `*T`. By Go's definition, it returns a pointer which points to type `T`'s zero-value. `new` returns pointers. -The built-in function `make(T, args)` has different purposes than `new(T)`. `make` can be used for `slice`, `map`, +The built-in function `make(T, args)` has different purposes than `new(T)`. `make` can be used for `slice`, `map`, and `channel`, and returns a type `T` with an initial value. The reason for doing this is because the underlying data of these three types must be initialized before they point to them. For example, a `slice` contains a pointer that points to the underlying `array`, length and capacity. Before these data are initialized, `slice` is `nil`, so for `slice`, `map` @@ -471,7 +471,7 @@ float32 0 // length is 4 byte 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 9813c984..4144dcd4 100644 --- a/en/02.3.md +++ b/en/02.3.md @@ -16,11 +16,11 @@ 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 +// initialize x, then check if x greater than if x := computedValue(); x > 10 { fmt.Println("x is greater than 10") } else { @@ -29,7 +29,7 @@ if x := computedValue(); x > 10 { // the following code will not compile fmt.Println(x) -``` +``` Use if-else for multiple conditions. ```Go if integer == 3 { @@ -39,7 +39,7 @@ if integer == 3 { } 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. @@ -51,7 +51,7 @@ Here: // label ends with ":" i++ goto Here // jump to label "Here" } -``` +``` The label name is case sensitive. ### for @@ -61,7 +61,7 @@ The label name is case sensitive. 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. @@ -87,14 +87,14 @@ 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-- { @@ -105,20 +105,28 @@ for index := 10; index>0; index-- { } // break prints 10、9、8、7、6 // continue prints 10、9、8、7、6、4、3、2、1 -``` +``` `for` can read data from `array`, `slice`, `map` and `string` when it is used together with `range`. ```Go -for k,v:=range map { +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. +``` +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. ```Go for _, v := range map{ fmt.Println("map's val:", v) } -``` +``` + +With go you can as well create an infinite loop, which is equivalent to `while true { ... }` in other languges. + +```GO +for { + // yout logic +} +``` ### 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. @@ -133,7 +141,7 @@ case expr3: 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 @@ -147,7 +155,7 @@ case 10: 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 @@ -170,7 +178,7 @@ case 8: default: fmt.Println("default case") } -``` +``` This program prints the following information. ```Go integer <= 6 @@ -187,7 +195,7 @@ func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) { // multi-value return return value1, value2 } -``` +``` We can extrapolate the following information from the example above. - Use keyword `func` to define a function `funcName`. @@ -196,7 +204,7 @@ We can extrapolate the following information from the example above. - There are two return values named `output1` and `output2`, you can omit their names and use their type only. - If there is only one return value and you omitted the name, you don't need brackets for the return values. - If the function doesn't have return values, you can omit the return parameters altogether. -- If the function has return values, you have to use the `return` statement somewhere in the body of the function. +- 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 @@ -210,9 +218,9 @@ func max(a, b int) int { return a } return b - } +} - func main() { +func main() { x := 3 y := 4 z := 5 @@ -224,8 +232,8 @@ func max(a, b int) int { 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 @@ -252,7 +260,7 @@ func main() { 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) { @@ -263,7 +271,7 @@ func SumAndProduct(A, B int) (add int, multiplied int) { ``` ### 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 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) {} ``` @@ -272,7 +280,7 @@ func myfunc(arg ...int) {} 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. @@ -299,7 +307,7 @@ func main() { 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. @@ -356,7 +364,7 @@ func ReadWrite() bool { 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. ```Go func ReadWrite() bool { @@ -370,19 +378,19 @@ func ReadWrite() bool { } 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 @@ -392,21 +400,14 @@ import "fmt" type testInt func(int) bool // define a function type of variable func isOdd(integer int) bool { - if integer%2 == 0 { - return false - } - return true + return integer%2 != 0 } func isEven(integer int) bool { - if integer%2 == 0 { - return true - } - return false + return integer%2 == 0 } // pass the function `f` as an argument to another function - func filter(slice []int, f testInt) []int { var result []int for _, value := range slice { @@ -417,16 +418,18 @@ func filter(slice []int, f testInt) []int { return result } +var slice = []int{1, 2, 3, 4, 5, 7} + func main() { - slice := []int{1, 2, 3, 4, 5, 7} - fmt.Println("slice = ", slice) - odd := filter(slice, isOdd) // use function as values + odd := filter(slice, isOdd) + even := filter(slice, isEven) + + fmt.Println("slice = ", slice) 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 @@ -446,7 +449,7 @@ func init() { panic("no value for $USER") } } -``` +``` The following example shows how to check `panic`. ```Go func throwsPanic(f func()) (b bool) { @@ -458,7 +461,7 @@ func throwsPanic(f func()) (b bool) { 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. @@ -478,18 +481,18 @@ We use `import` very often in Go programs as follows. 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 import "./model" // load package in the same directory, I don't recommend this way. 2. Absolute path import "shorturl/model" // load package in path "$GOPATH/pkg/shorturl/model" - + There are some special operators when we import packages, and beginners are always confused by these operators. 1. Dot operator. @@ -502,7 +505,7 @@ import( 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 +```Go import( f "fmt" ) @@ -510,14 +513,14 @@ import( 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 +```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 - [Directory](preface.md)