Add Add en/0.2.3.md syntax highlighting

This commit is contained in:
vCaesar
2017-04-09 14:46:53 +08:00
parent e3aab44bff
commit 2a9a362c56
2 changed files with 177 additions and 170 deletions

View File

@@ -84,14 +84,15 @@ More examples.
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!*** ) 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 ```Go
// sample code // sample code
var isActive bool // global variable var isActive bool // global variable
var enabled, disabled = true, false // omit type of variables var enabled, disabled = true, false // omit type of variables
func test() {
var available bool // local variable func test() {
valid := false // brief statement of variable var available bool // local variable
available = true // assign value to variable valid := false // brief statement of variable
} available = true // assign value to variable
}
``` ```
### Numerical types ### Numerical types

View File

@@ -11,15 +11,15 @@ The greatest invention in programming is flow control. Because of them, you are
`if` will most likely be the most common keyword in your programs. If it meets the conditions, then it does something and it does something else if not. `if` 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. `if` doesn't need parentheses in Go.
```Go
if x > 10 { if x > 10 {
fmt.Println("x is greater than 10") fmt.Println("x is greater than 10")
} else { } else {
fmt.Println("x is less than or equal to 10") 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`. 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 { if x := computedValue(); x > 10 {
fmt.Println("x is greater than 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 // the following code will not compile
fmt.Println(x) fmt.Println(x)
```
Use if-else for multiple conditions. Use if-else for multiple conditions.
```Go
if integer == 3 { if integer == 3 {
fmt.Println("The integer is equal to 3") fmt.Println("The integer is equal to 3")
} else if integer < 3 { } else if integer < 3 {
@@ -39,11 +39,11 @@ Use if-else for multiple conditions.
} else { } else {
fmt.Println("The integer is greater than 3") fmt.Println("The integer is greater than 3")
} }
```
### goto ### 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 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() { func myFunc() {
i := 0 i := 0
Here: // label ends with ":" 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++ i++
goto Here // jump to label "Here" goto Here // jump to label "Here"
} }
```
The label name is case sensitive. The label name is case sensitive.
### for ### for
`for` is the most powerful control logic in Go. It can read data in loops and iterative operations, just like `while`. `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 { 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. `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. Examples are more useful than words.
```Go
package main package main
import "fmt" import "fmt"
@@ -77,25 +77,25 @@ Examples are more useful than words.
fmt.Println("sum is equal to ", sum) fmt.Println("sum is equal to ", sum)
} }
// Printsum is equal to 45 // Printsum is equal to 45
```
Sometimes we need multiple assignments, but Go doesn't have the `,` operator, so we use parallel assignment like `i, j = i + 1, j - 1`. 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. We can omit `expression1` and `expression3` if they are not necessary.
```Go
sum := 1 sum := 1
for ; sum < 1000; { for ; sum < 1000; {
sum += sum sum += sum
} }
```
Omit `;` as well. Feel familiar? Yes, it's identical to `while`. Omit `;` as well. Feel familiar? Yes, it's identical to `while`.
```Go
sum := 1 sum := 1
for sum < 1000 { for sum < 1000 {
sum += sum 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. 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-- { for index := 10; index>0; index-- {
if index == 5{ if index == 5{
break // or continue 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 // break prints 10、9、8、7、6
// continue prints 10、9、8、7、6、4、3、2、1 // 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`. `for` can read data from `slice` and `map` 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 key:",k)
fmt.Println("map's val:",v) 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.
for _, v := range map{ for _, v := range map{
@@ -121,7 +121,7 @@ Because Go supports multi-value returns and gives compile errors when you don't
### switch ### 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. 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 { switch sExpr {
case expr1: case expr1:
some instructions some instructions
@@ -132,9 +132,9 @@ Sometimes you may find that you are using too many `if-else` statements to imple
default: default:
other code 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`. 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 i := 10
switch i { switch i {
case 1: case 1:
@@ -146,9 +146,9 @@ The type of `sExpr`, `expr1`, `expr2`, and `expr3` must be the same. `switch` is
default: default:
fmt.Println("All I know is that i is an integer") 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. 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 integer := 6
switch integer { switch integer {
case 4: 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: default:
fmt.Println("default case") fmt.Println("default case")
} }
```
This program prints the following information. This program prints the following information.
```Go
integer <= 6 integer <= 6
integer <= 7 integer <= 7
integer <= 8 integer <= 8
default case default case
```
## Functions ## Functions
Use the `func` keyword to define a function. Use the `func` keyword to define a function.
```Go
func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) { func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) {
// function body // function body
// multi-value return // multi-value return
return value1, value2 return value1, value2
} }
```
We can extrapolate the following information from the example above. We can extrapolate the following information from the example above.
- Use keyword `func` to define a function `funcName`. - 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. - 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) 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 // return greater value between a and b
func max(a, b int) int { func max(a, b int) int {
if a > b { if a > b {
return a return a
}
return b
} }
return b
}
func main() { func main() {
x := 3 x := 3
y := 4 y := 4
z := 5 z := 5
max_xy := max(x, y) // call function max(x, y) max_xy := max(x, y) // call function max(x, y)
max_xz := max(x, z) // call function max(x, z) 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, y, max_xy)
fmt.Printf("max(%d, %d) = %d\n", x, z, max_xz) 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", 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. 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 ### 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. One thing that Go is better at than C is that it supports multi-value returns.
We'll use the following example here. We'll use the following example here.
```Go
package main
package main import "fmt"
import "fmt"
// return results of A + B and A * B // return results of A + B and A * B
func SumAndProduct(A, B int) (int, int) { func SumAndProduct(A, B int) (int, int) {
return A+B, A*B return A + B, A * B
} }
func main() { func main() {
x := 3 x := 3
y := 4 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. 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) { func SumAndProduct(A, B int) (add int, multiplied int) {
add = A+B add = A+B
multiplied = A*B multiplied = A*B
return return
} }
```
### Variadic functions ### 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) {} 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`. `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 { for _, n := range arg {
fmt.Printf("And the number is: %d\n", n) fmt.Printf("And the number is: %d\n", n)
} }
```
### Pass by value and pointers ### 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. 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. 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 // simple function to add 1 to a
func add1(a int) int { func add1(a int) int {
a = a+1 // we change value of a a = a + 1 // we change value of a
return a // return new value of a return a // return new value of a
} }
func main() { func main() {
x := 3 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. 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. The reason is very simple: when we called `add1`, we gave a copy of `x` to it, not the `x` itself.
@@ -302,7 +306,7 @@ 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. 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. 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"
@@ -322,7 +326,7 @@ We need use pointers here. We know variables are stored in memory and they have
fmt.Println("x+1 = ", x1) // should print "x+1 = 4" fmt.Println("x+1 = ", x1) // should print "x+1 = 4"
fmt.Println("x = ", x) // should print "x = 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? 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. - Allows us to use more functions to operate on one variable.
@@ -332,92 +336,94 @@ Now we can change the value of `x` in the functions. Why do we use pointers? Wha
### defer ### 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. 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.
```Go
func ReadWrite() bool { func ReadWrite() bool {
file.Open("file") file.Open("file")
// Do some work // Do some work
if failureX { if failureX {
file.Close() file.Close()
return false return false
}
if failureY {
file.Close()
return false
}
file.Close()
return true
} }
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. 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 { func ReadWrite() bool {
file.Open("file") file.Open("file")
defer file.Close() defer file.Close()
if failureX { if failureX {
return false return false
}
if failureY {
return false
}
return true
} }
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`. 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++ { for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i) defer fmt.Printf("%d ", i)
} }
```
### Functions as values and types ### 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. 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 [, ...]) 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. 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 { func isOdd(integer int) bool {
if integer%2 == 0 { if integer%2 == 0 {
return false return false
}
return true
} }
return true
}
func isEven(integer int) bool { func isEven(integer int) bool {
if integer%2 == 0 { if integer%2 == 0 {
return true return true
}
return false
} }
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 { func filter(slice []int, f testInt) []int {
var result []int var result []int
for _, value := range slice { for _, value := range slice {
if f(value) { if f(value) {
result = append(result, value) result = append(result, value)
} }
}
return result
} }
return result
}
func main(){ func main() {
slice := []int {1, 2, 3, 4, 5, 7} slice := []int{1, 2, 3, 4, 5, 7}
fmt.Println("slice = ", slice) fmt.Println("slice = ", slice)
odd := filter(slice, isOdd) // use function as values odd := filter(slice, isOdd) // use function as values
fmt.Println("Odd elements of slice are: ", odd) fmt.Println("Odd elements of slice are: ", odd)
even := filter(slice, isEven) even := filter(slice, isEven)
fmt.Println("Even elements of slice are: ", even) 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. 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 ### Panic and Recover
@@ -429,7 +435,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. `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`. The following example shows how to use `panic`.
```Go
var user = os.Getenv("USER") var user = os.Getenv("USER")
func init() { func init() {
@@ -437,9 +443,9 @@ The following example shows how to use `panic`.
panic("no value for $USER") panic("no value for $USER")
} }
} }
```
The following example shows how to check `panic`. The following example shows how to check `panic`.
```Go
func throwsPanic(f func()) (b bool) { func throwsPanic(f func()) (b bool) {
defer func() { defer func() {
if x := recover(); x != nil { if x := recover(); x != nil {
@@ -449,7 +455,7 @@ The following example shows how to check `panic`.
f() // if f causes panic, it will recover f() // if f causes panic, it will recover
return return
} }
```
### `main` function and `init` function ### `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. 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 +471,15 @@ Figure 2.6 Flow of programs initialization in Go
### import ### import
We use `import` very often in Go programs as follows. We use `import` very often in Go programs as follows.
```Go
import( import(
"fmt" "fmt"
) )
```
Then we use functions in that package as follows. Then we use functions in that package as follows.
```Go
fmt.Println("hello world") fmt.Println("hello world")
```
`fmt` is from Go standard library, it is located within $GOROOT/pkg. Go supports third-party packages in two ways. `fmt` is from Go standard library, it is located within $GOROOT/pkg. Go supports third-party packages in two ways.
1. Relative path 1. Relative path
@@ -485,28 +491,28 @@ There are some special operators when we import packages, and beginners are alwa
1. Dot operator. 1. Dot operator.
Sometime we see people use following way to import packages. Sometime we see people use following way to import packages.
```Go
import( import(
. "fmt" . "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")`. 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. 2. Alias operation.
It changes the name of the package that we imported when we call functions that belong to that package. It changes the name of the package that we imported when we call functions that belong to that package.
```Go
import( import(
f "fmt" f "fmt"
) )
```
Now `fmt.Printf("Hello world")` becomes to `f.Printf("Hello world")`. Now `fmt.Printf("Hello world")` becomes to `f.Printf("Hello world")`.
3. `_` operator. 3. `_` operator.
This is the operator that is difficult to understand without someone explaining it to you. This is the operator that is difficult to understand without someone explaining it to you.
```Go
import ( import (
"database/sql" "database/sql"
_ "github.com/ziutek/mymysql/godrv" _ "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. 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 ## Links