From 5315ab318eacd118440ff7c5c50670a685d7d8bc Mon Sep 17 00:00:00 2001 From: ldynia Date: Sun, 16 Jul 2017 15:30:30 +0200 Subject: [PATCH 1/4] 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) From cf5a39886db5fbb32b763a911c6bf6223d61be87 Mon Sep 17 00:00:00 2001 From: ldynia Date: Sun, 16 Jul 2017 18:29:38 +0200 Subject: [PATCH 2/4] fixing code formating and removing redundant comments --- en/02.4.md | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/en/02.4.md b/en/02.4.md index e80360da..edd8f818 100644 --- a/en/02.4.md +++ b/en/02.4.md @@ -8,7 +8,7 @@ type person struct { name string age int } -``` +``` Look how easy it is to define a `struct`! There are two fields. @@ -34,7 +34,7 @@ There are three more ways to define a struct. - Assign initial values by order ```Go P := person{"Tom", 25} -``` +``` - Use the format `field:value` to initialize the struct without order ```Go P := person{age:24, name:"Bob"} @@ -44,6 +44,7 @@ P := person{age:24, name:"Bob"} P := struct{name string; age int}{"Amy",18} ``` Let's see a complete example. + ```Go package main @@ -55,8 +56,8 @@ type person struct { age int } -// compare the age of two people, then return the older person and differences of age // struct is passed by value +// compare the age of two people, then return the older person and differences of age func Older(p1, p2 person) (person, int) { if p1.age > p2.age { return p1, p1.age - p2.age @@ -67,13 +68,8 @@ func Older(p1, p2 person) (person, int) { func main() { var tom person - // initialization tom.name, tom.age = "Tom", 18 - - // initialize two values by format "field:value" bob := person{age: 25, name: "Bob"} - - // initialize two values with order paul := person{"Paul", 43} tb_Older, tb_diff := Older(tom, bob) @@ -81,13 +77,10 @@ func main() { 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, 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) } - -``` +``` ### 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. @@ -112,7 +105,7 @@ type Student struct { } func main() { - // initialize a student + // instantiate and initialize a student mark := Student{Human{"Mark", 25, 120}, "Computer Science"} // access fields @@ -120,21 +113,20 @@ func main() { fmt.Println("His age is ", mark.age) fmt.Println("His weight is ", mark.weight) fmt.Println("His specialty is ", mark.specialty) - // modify notes + + // modify mark's specialty mark.specialty = "AI" fmt.Println("Mark changed his specialty") fmt.Println("His specialty is ", mark.specialty) - // modify age - fmt.Println("Mark become old") + + fmt.Println("Mark become old. He is not an athlete anymore") 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 age is", mark.age) fmt.Println("His weight is", mark.weight) } -``` +``` ![](images/2.4.student_struct.png?raw=true) Figure 2.7 Embedding in Student and Human @@ -143,7 +135,7 @@ We see that we can access the `age` and `name` fields in Student just like we ca ```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 @@ -184,7 +176,7 @@ func main() { 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? @@ -202,19 +194,19 @@ type Human struct { } type Employee struct { - Human // embedded field Human + 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) } -``` +``` ## Links - [Directory](preface.md) From 367ff44de62f87f3d18231f9e49004085fe78b03 Mon Sep 17 00:00:00 2001 From: ldynia Date: Sun, 16 Jul 2017 19:00:19 +0200 Subject: [PATCH 3/4] improving this chapter --- en/02.5.md | 106 +++++++++++++++++++++++++++-------------------------- 1 file changed, 55 insertions(+), 51 deletions(-) diff --git a/en/02.5.md b/en/02.5.md index 32b92927..21b57a6b 100644 --- a/en/02.5.md +++ b/en/02.5.md @@ -1,6 +1,6 @@ # Object-oriented -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`. +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 a `method`. ## method @@ -25,7 +25,7 @@ func main() { 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. @@ -36,18 +36,18 @@ Figure 2.8 Relationship between function and struct Obviously that's not cool. Also, the area should really be the property of a circle or rectangle. -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. +This is where a `method` comes to play. The `method` is a function affiliated with a type. It has similar syntax as function except, after the `func` keyword has a parameter called the `receiver`, which is the main body of that method. -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. +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. As Rob Pike said. "A method is a function with an implicit first argument, called a receiver." - + Syntax of method. ```Go func (r ReceiverType) funcName(parameters) (results) -``` +``` Let's change our example using `method` instead. ```Go package main @@ -57,46 +57,48 @@ import ( "math" ) -type Rectangle struct { - width, height float64 -} - type Circle struct { radius float64 } -func (r Rectangle) area() float64 { - return r.width * r.height +type Rectangle struct { + width, height float64 } -func (c Circle) area() float64 { +// method +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} - - 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()) +// method +func (r Rectangle) Area() float64 { + return r.width * r.height } -``` +func main() { + c1 := Circle{10} + c2 := Circle{25} + r1 := Rectangle{9, 4} + r2 := Rectangle{12, 2} + + 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()) +} +``` + 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. +- Use `.` to call a method in the struct, the same way fields are called. ![](images/2.5.shapes_func_with_receiver_cp.png?raw=true) Figure 2.9 Methods are different in different structs -In the example above, the area() methods belong to both Rectangle and Circle respectively, so the receivers are Rectangle and Circle. +In the example above, the Area() methods belong to both Rectangle and Circle respectively, so the receivers are Rectangle and 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. @@ -105,13 +107,12 @@ Can the receiver only be a struct? Of course not. Any type can be the receiver o Use the following format to define a customized type. ```Go type typeName typeLiteral -``` +``` Examples of customized types: + ```Go -type ages int - +type age int type money float32 - type months map[string]int m := months { @@ -120,7 +121,8 @@ m := months { ... "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`. @@ -139,23 +141,24 @@ const ( YELLOW ) -type Color byte - type Box struct { width, height, depth float64 - color Color + color Color } - +type Color byte type BoxList []Box //a slice of boxes +// method func (b Box) Volume() float64 { return b.width * b.height * b.depth } +// method with a pointer receiver func (b *Box) SetColor(c Color) { b.color = c } +// method func (bl BoxList) BiggestsColor() Color { v := 0.00 k := Color(WHITE) @@ -168,12 +171,14 @@ func (bl BoxList) BiggestsColor() Color { return k } +// method func (bl BoxList) PaintItBlack() { for i, _ := range bl { bl[i].SetColor(BLACK) } } +// method func (c Color) String() string { strings := []string{"WHITE", "BLACK", "BLUE", "RED", "YELLOW"} return strings[c] @@ -194,14 +199,14 @@ func main() { 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") + // Let's paint them all black boxes.PaintItBlack() - fmt.Println("The color of the second one is", boxes[1].color.String()) + 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`. @@ -210,11 +215,11 @@ We define some constants and customized types. Then we defined some methods for our customized types. -- Volume() uses Box as its receiver and returns the 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. +- `Volume()` uses Box as its receiver and returns the 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. Is it much clearer when we use words to describe our requirements? We often write our requirements before we start coding. @@ -224,13 +229,13 @@ Let's take a look at `SetColor` method. Its receiver is a pointer of Box. Yes, y If we see that a receiver is the first argument of a method, it's not hard to understand how it works. -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? +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? 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! ### 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. +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 @@ -258,13 +263,12 @@ func (h *Human) SayHi() { } func main() { - mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"} sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"} + mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"} - mark.SayHi() sam.SayHi() + mark.SayHi() } - ``` ### Method overload @@ -300,14 +304,14 @@ func (e *Employee) SayHi() { } func main() { - mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"} sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"} + mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"} - mark.SayHi() sam.SayHi() + mark.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 From 8b460337bf421f18befd5f5deae971d4ff36b14d Mon Sep 17 00:00:00 2001 From: ldynia Date: Sun, 16 Jul 2017 19:32:51 +0200 Subject: [PATCH 4/4] improving chapter 2.6 --- en/02.6.md | 133 ++++++++++++++++++++++++++++------------------------- 1 file changed, 70 insertions(+), 63 deletions(-) diff --git a/en/02.6.md b/en/02.6.md index 39762095..615eaa88 100644 --- a/en/02.6.md +++ b/en/02.6.md @@ -20,7 +20,6 @@ This combination of methods is called an interface and is implemented by both St 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 @@ -39,33 +38,7 @@ type Employee struct { 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 la, la la la la la...", lyrics) -} - -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. -} - -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! -} - -// define interface +// define interfaces type Men interface { SayHi() Sing(lyrics string) @@ -84,6 +57,31 @@ type ElderlyGent interface { SpendSalary(amount 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 la, la la la la la...", lyrics) +} + +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. +} + +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! +} ``` We know that an interface can be implemented by any type, and one type can implement many interfaces simultaneously. @@ -117,25 +115,28 @@ type Employee struct { 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) } +// method +func (h Human) SayHi() { + fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone) +} + +// method +func (h Human) Sing(lyrics string) { + fmt.Println("La la la la...", lyrics) +} + +// method +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() { mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00} paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100} @@ -167,8 +168,7 @@ func main() { 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 @@ -176,25 +176,29 @@ An interface is a set of abstract methods, and can be implemented by non-interfa 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 +var void interface{} + +// vars +i := 5 s := "Hello world" + // a can store value of any type -a = i -a = s +void = i +void = 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 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. +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. ```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 @@ -210,7 +214,7 @@ type Human struct { phone string } -// Human implemented fmt.Stringer +// Human implements fmt.Stringer func (h Human) String() string { return "Name:" + h.name + ", Age:" + strconv.Itoa(h.age) + " years, Contact:" + h.phone } @@ -219,18 +223,18 @@ 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 -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. +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. - Assertion of Comma-ok pattern @@ -284,7 +288,7 @@ It's quite easy to use this pattern, but if we have many types to test, we'd bet - switch test Let's use `switch` to rewrite the above example. -```Go +```Go package main import ( @@ -325,7 +329,7 @@ func main() { } ``` - + 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 @@ -351,7 +355,7 @@ type Interface interface { // Swap swaps the elements with indexes i and j. Swap(i, j int) } -``` +``` Another example is the `io.ReadWriter` in package `io`. ```Go // io.ReadWriter @@ -359,30 +363,33 @@ 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 in Go is used for determining information at runtime. We use the `reflect` package, and [The Laws of Reflection](http://golang.org/doc/articles/laws_of_reflection.html) post 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 + +t := reflect.TypeOf(x) v := reflect.ValueOf(x) -fmt.Println("type:", v.Type()) + +fmt.Println("type:", t) +fmt.Println("value:", v) 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