Introduction:
Google language is the most popular programming language in recent years. It is a static, compiled, concurrent programming language developed by Google with garbage collection function. GoLanguage has two characteristics: high development efficiency and high execution efficiency. It is known as C language in the era of cloud computing. The author of this article takes you to learn the Go language through an article.
Go language is an open source language, which can easily build simple, reliable and efficient software.
- Golang
In many languages, there are usually many ways to solve a given problem. Engineers need to spend a lot of time thinking about what is the best solution to the problem. In Golang, there is usually only one solution to the problem.
This feature saves engineers a lot of time and makes it easier to maintain large code bases. There is no such "high consumption" feature as maps and filter s in Golang.
Language features bring about better expressiveness and cost.
-Rob Pike
1. Start
Golang consists of packages. The Golang compiler compiles main packages into executable files rather than shared libraries. The main package is the entry point to the application and is usually defined as follows:
package main
Let's look at an example of hello world, creating the main.go file in Golang's workspace.
1.1 workspace
In Go, the workspace is defined by the environment variable GOPATH. All written code needs to be in the workspace. The Go language searches for packages in the paths of GOPATH and GOROOT. GoROOT is the installation path determined at the time of installation.
Let's set up GOPATH and add ~/workspace to the workspace.
# export env export GOPATH=~/workspace # go inside the workspace cd ~/workspace
1.2 HELLO WORLD!
We created the main.go file in the workspace just now. The code is as follows:
package main import ( "fmt" ) func main(){ fmt.Println("Hello World!") }
In the example above, fmt is the formatted I/O function built into Go.
We use the import keyword to import packages in Go, and func main is the entry function. Println is a function in the fmt package that prints "Hello World!".
Let's start running the file. As we all know, Go is a compiled language. We compile it before we run it.
go build main.go
This will create a binary run file main, which we will run now:
./main // Hello World!
Another simple way is to use the go run command:
go run main.go // Hello World!
2. Variables
The variable type in Go is explicitly specified. The Go language is strongly typed, which means that variable types are checked when variables are declared.
Variable definitions are as follows:
var a int In this example, the initial value of a is set to 0. Variables can be defined and initialized in the following way. var a = 1 The variables here are inferred to be int by the compiler. Simpler variable definitions are as follows: message := "hello world" We can also declare multiple variables on the same line: var b, c int = 2, 3
3. Data type
3.1 NUMBER,STRING, BOOLEAN
The types of int are int, int8, int16, int32, int64, unit, unit 8, unit 16, unit 32, unit 64, unit PTR..
[u begins with unsigned; uintptr is an unsigned integer type that does not specify a specific bit size but is large enough to hold pointers. The uintptr type is required only for low-level programming, especially where the Go and C language function libraries or operating system interfaces interact. ]
String type uses byte sequence to store data and keyword string to declare variables.
bool keywords denote Boolean types.
Golang also supports complex numbers, expressed in conplex64 and complex128.
var a bool = true vat b int = 1 var c string = "hello world" var d float32 = 1.222 var x complex128 = cmplx.Sqrt(-5 +12i)
3.2 ARRAYS,SLICES,MAPS
Array is an array of elements of the same type. Array specifies the length of the declaration and cannot change it. An array is defined as follows:
var a[5] int There are also multidimensional arrays, defined as follows var multiD [2][3]int Slices are sequences of elements of the same type that can be expanded at any time. Slice's declaration is as follows: var b []int This will create a Slice with a capacity of 0 and a length of 0. Slice can also define capacity and length in the following format: numbers := make([]int, 5, 10) The Slice has an initial length of 5 and a capacity of 10.
Slice is the encapsulation of an array, and its internal implementation is an array. Slice has three elements, capacity, length and pointer to the internal array.
Slice's capacity can be increased by append or copy functions. The Append function can also add elements at the end of the array, expanding slice in case of insufficient capacity.
numbers = append(numbers, 1, 2, 3, 4) Another way to increase slice capacity is to use the copy function. The principle of Copy function is to create a new large capacity slice and copy the original slice into the new slice. // Create a new slice number2 := make([]int, 15) // Duplicate the original slice to the new slice copy(number2, number)
We can also create slice's sub-slice. Examples are as follows:
package main import ( "fmt" ) func main() { // Initialize slice number2 := []int{1, 2, 3, 4} fmt.Println(number2) // -> [1 2 3 4] // Create subslice slice1 := number2[2:] fmt.Println(slice1) // -> [3 4] slice2 := number2[:3] fmt.Println(slice2) // -> [1 2 3] slice3 := number2[1:4] fmt.Println(slice3) // -> [2 3 4] }
Map in Go language is a key-value pair, which is defined as follows:
var m map[string]int
m is the variable name defined, the key type is string, and the value type is integers. An example of adding key-value pairs to a Map is as follows:
package main import ( "fmt" ) func main() { m := make(map[string]int) // Adding key-value pairs m["clearity"] = 2 m["simplicity"] = 3 // Print value fmt.Println(m["clearity"]) // -> 2 fmt.Println(m["simplicity"]) // -> 3 }
4. Type Conversion
Using type conversions can change data types. Examples are as follows:
package main import ( "fmt" ) func increment(i *int) { *i++ } func main() { a := 1.1 b := int(a) fmt.Println(b) //-> 1 }
5. Conditional expressions
5.1 IF ELSE
If else's example is as follows, it's important to note that curly braces and conditional expressions are on the same line.
package main import ( "fmt" ) func increment(i *int) { *i++ } func main() { if num := 9; num < 0 { fmt.Println(num, "is negative") } else if num < 10 { fmt.Println(num, "has 1 digit") } else { fmt.Println(num, "has multiple digits") } }
5.2 SWITCH CASE
Switch case can organize multi-conditional expressions. Examples are as follows:
package main import ( "fmt" ) func increment(i *int) { *i++ } func main() { i := 2 switch i { case 1: fmt.Println("one") case 2: fmt.Println("two") default: fmt.Println("none") } }
5.3 Cycle
There is only one keyword in Golang that is expressed in a loop. The different forms of loop expressions are as follows:
package main import ( "fmt" ) func increment(i *int) { *i++ } func main() { i := 0 sum := 0 for i < 10 { sum += 1 i++ } fmt.Println(sum) }
The example above is similar to the while loop in C, and the more formal form of the loop is as follows:
package main import ( "fmt" ) func increment(i *int) { *i++ } func main() { sum := 0 for i := 0; i < 10; i++ { sum += i } fmt.Println(sum) }
Dead loops in Go are defined as follows:
for { }
6. Pointer
The Go language can use pointers, which store the address of variables, and pointers are defined by *. The definition of pointers is related to the type of data they refer to:
var ap *int Here ap is a pointer to integer data & used to get the address of the variable. a :=12 ap = &a * Used to get the value of the address indicated by the pointer. fmt.Println(*ap) // => 12 Pointer is usually used to pass the structure as a parameter.
Passing values usually means copying, meaning more memory is needed.
With pointer passing, variables that change in a function are passed to the calling method or function.
package main import ( "fmt" ) func increment(i *int) { *i++ } func main() { i := 10 increment(&i) fmt.Println(i) //=> 11 }
7. Functions
The main function in the main package is the entry to the golang program. We can define multiple functions and call them. For example:
package main import ( "fmt" ) func add(a int, b int) int { c := a + b return c } func main() { fmt.Println(add(2, 1)) //=> 3 }
From the example above, we can see that the function in Golang uses the func keyword plus the function name, followed by the parameters of the attached data type, and finally the return type of the function.
The return value of a function can be predefined as follows:
package main import ( "fmt" ) func add(a int, b int) (c int) { c = a + b return } func main() { fmt.Println(add(2, 1)) //=> 3 }
Here c is defined as the return value, so the variable c will be returned automatically without having to be declared in the final return of the function.
You can also define a function with multiple return values, use it, and split it.
package main import ( "fmt" ) func add(a int, b int) (int, string) { c := a + b return c, "successfully added" } func main() { sum, message := add(2, 1) fmt.Println(message) //=> successfully added fmt.Println(sum) //=> 3 }
8. Methods, Structures, Interfaces
Golang is not a fully object-oriented language, but it supports many object-oriented features, such as structure, interface, method, etc.
8.1 Structure
Structures are a collection of different types and variables. For example, we want to define the Person type, which includes name, age and gender. For example:
type person struct { name String age int gender string }
Having defined the person structure, let's use it now:
// Mode 1: Specify attributes and values p = person{name: "Bob", age: 42, gender: "Male"} // Mode 2: Specify only values person{"Bob", 42, "Male"} We can use. symbols to access these properties: p.name //=> Bob p.age //=> 42 p.gender //=> Male
You can also use pointers to access attributes of a structure:
pp = &person{name: "Bob", age: 42, gender: "Male"} pp.name //=> Bob
8.2 Method
The method is a special function with a receiver. The receiver can be a value or a pointer. Examples are as follows:
package main import "fmt" // Defining Structures type person struct { name string age int gender string } // Definition method func (p *person) describe() { fmt.Printf("%v is %v years old.", p.name, p.age) } func (p *person) setAge(age int) { p.age = age } func (p person) setName(name string) { p.name = name } func main() { pp := &person{name: "Bob", age: 42, gender: "Male"} pp.describe() // => Bob is 42 years old pp.setAge(45) fmt.Println(pp.age) //=> 45 pp.setName("Hari") fmt.Println(pp.name) //=> Bob }
From the example above, we can see that methods are invoked using. operators, such as pp.describe. It should be noted that if the receiver is a pointer, we pass a reference to the value, which means that our method modification will be reflected on the variable pp. This will not create a copy of the object, which will save memory.
From the above example, we can see that the value of age has been changed, while the value of name has not changed. This is because the receiver of the method setName is not a pointer.
8.3 Interface
Interfaces in Golang are collections of methods. Interfaces help to combine attributes of the same type. Let's look at an anminal interface.
type animal interface { description() string }
Here animal is the interface type. Let's create two types of animal and implement the interface.
package main import ( "fmt" ) type animal interface { description() string } type cat struct { Type string Sound string } type snake struct { Type string Poisonous bool } func (s snake) description() string { return fmt.Sprintf("Poisonous: %v", s.Poisonous) } func (c cat) description() string { return fmt.Sprintf("Sound: %v", c.Sound) } func main() { var a animal a = snake{Poisonous: true} fmt.Println(a.description()) a = cat{Sound: "Meow!!!"} fmt.Println(a.description()) } //=> Poisonous: true //=> Sound: Meow!!!
In the main function, we create a variable a of animal type. We assign snake and cat types to animals and use Println to output a.description.
We implemented the description method in different ways in cat and snake, and we got different types of output.
9. packs
In Golang, our code is under a package. The main package is the entry point for program execution. There are many built-in packages in Go, such as the fmt packages we used before.
Go's package mechanism is the foundation of large software, which can break down large projects into small parts.
- Robert Griesemer
9.1 Install a package
go get
// Example go get github.com/satori/go.uuid
The installed packages are stored in the GOPATH environment, and you can see the installed packages in the $GOPATH/pkg path.
9.2 Create a custom package
First create a folder custom_package:
mkdir custom_package cd custom_package
The first step in creating a custom package is to create a folder with the same package name. We want to create the person package, so we create the person folder under the custom_package file:
mkdir person cd person
Under this path, create a file person.go:
package person func Description(name string) string { return "The person name is: " + name } func secretName(name string) string { return "Do not share" }
Now let's install the package so that we can import and use it:
go install
Next, we return to the custom_package folder and create a main.go:
package main import ( "custom_package/person" "fmt" ) func main() { p := person.Description("Milap") fmt.Println(p) } // => The person name is: Milap
Here, we can import the previously created package person. It should be noted that the function secretName in the person package cannot be accessed because the function at the beginning of the upper and lower case letters of Go is a private function.
9.3 Generating Package Documents
There are built-in features in Golang to support package documents. Running the following command generates the document:
godoc person Description
This will generate the document for the Description function. To view the document on the web server, you need to run the following command:
godoc -http=":8080"
Now open the link http://localhost 8080/pkg/will see the document we just saw.
9.4 Go built-in packages
9.4.1 fmt
The fmt package implements standard I/O functions, among which we used print output functions in previous packages.
9.4.2 json
Another important built-in package in Golang is json, which can encode and decode JSON.
Code
package main import ( "encoding/json" "fmt" ) func main() { mapA := map[string]int{"apple": 5, "lettuce": 7} mapB, _ := json.Marshal(mapA) fmt.Println(string(mapB)) }
Decode
package main import ( "encoding/json" "fmt" ) type response struct { PageNumber int json:"page" Fruits []string json:"fruits" } func main() { str := {"page": 1, "fruits": ["apple", "peach"]} res := response{} json.Unmarshal([]byte(str), &res) fmt.Println(res.PageNumber) } //=> 1
Unmarshal method is used when decoding. The first parameter is json byte, and the second parameter is the address of the structure to be mapped. It should be noted that "page" in json corresponds to PageNumber in the structure.
10. Error handling
Errors are results that should not occur in a program. Suppose we write an API to invoke external services. This API may succeed or fail. When there are errors, the Golang program can identify:
resp, err := http.Get("http://example.com/")
API calls may succeed or fail, and we can choose how to handle them by checking whether the error is empty.
package main import ( "fmt" "net/http" ) func main() { resp, err := http.Get("http://example.com/") if err != nil { fmt.Println(err) return } fmt.Println(resp) }
10.1 Returns custom errors from functions
When we define a function that is, in some cases, an error will occur. We can use the error object to return these errors:
package main import ( "errors" "fmt" ) func Increment(n int) (int, error) { if n < 0 { // return error object return 0, errors.New("math: cannot process negative number") } return (n + 1), nil } func main() { num := 5 if inc, err := Increment(num); err != nil { fmt.Printf("Failed Number: %v, error message: %v", num, err) } else { fmt.Printf("Incremented Number: %v", inc) } } // => The person name is: Milap
Go's built-in packages and external packages have error handling mechanisms. So all the functions we call are likely to produce errors. These errors should not be ignored, but should be handled gracefully as the examples above.
10.2 Panic
Panic is an unprocessed exception that occurs suddenly in the running of a program. In Go, panic is not a reasonable way to handle exceptions, and error objects are recommended instead. When Panic is generated, the program will be suspended. When panic is defer, the program can continue to run.
//Go package main import "fmt" func main() { f() fmt.Println("Returned normally from f.") } func f() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered in f", r) } }() fmt.Println("Calling g.") g(0) fmt.Println("Returned normally from g.") } func g(i int) { if i > 3 { fmt.Println("Panicking!") panic(fmt.Sprintf("%v", i)) } defer fmt.Println("Defer in g", i) fmt.Println("Printing in g", i) g(i + 1) }
10.3 Defer
Defer must be executed at the end of the function. In the above function, panic() is used to suspend the running of the program, and defer statement makes the program use a line change at the end of execution. Defer can also be used as a statement that we want to execute at the end of a function, such as closing a file.
11. Concurrent
Golong supports concurrency using lightweight thread Go routies.
11.1 Go routine
Go routine is a function that can run in parallel. Creating Go routine is very simple, just add the keyword go before the function, so that the function can run in parallel. Go routines are lightweight, and we can create thousands of Go routines. For example:
package main import ( "fmt" "time" ) func main() { go c() fmt.Println("I am main") time.Sleep(time.Second * 2) } func c() { time.Sleep(time.Second * 2) fmt.Println("I am concurrent") } //=> I am main //=> I am concurrent
In the example above, function c is Go routine, which can run in parallel. We want to share resources in multithreading, but Golang does not support it. Because this leads to deadlocks and resource waiting. Go provides another way to share resources: channel.
11.2 Channels
We can use Channel to transfer data between two Go routine s. Before creating channel, you need to specify the type of data you accept. For example, we created a channel that accepts string type.
c := make(chan string)
With this channel, we can send and receive string-type data through this channel.
package main import "fmt" func main() { c := make(chan string) go func() { c <- "hello" }() msg := <-c fmt.Println(msg) //=>"hello" }
The received channel waits for the transmitted channel to send data.
11.3 One way channel
In some cases, we want Go routine to receive data through channel, but not send data, and vice versa. At this point we can create a one-way channel. For example:
package main import ( "fmt" ) func main() { ch := make(chan string) go sc(ch) fmt.Println(<-ch) } func sc(ch chan<- string) { ch <- "hello" }
In the example above, sc is a Go routine that can only send data to channel but cannot accept data.
12. Using selecct to optimize multiple channel s
In this case, a function waits for more than one channel, at which point we can use the select statement. For example:
package main import ( "fmt" "time" ) func main() { c1 := make(chan string) c2 := make(chan string) go speed1(c1) go speed2(c2) fmt.Println("The first to arrive is:") select { case s1 := <-c1: fmt.Println(s1) case s2 := <-c2: fmt.Println(s2) } } func speed1(ch chan string) { time.Sleep(2 * time.Second) ch <- "speed 1" } func speed2(ch chan string) { time.Sleep(1 * time.Second) ch <- "speed 2" }
In the example above, the main function waits for two channels, c1 and c2. Using the select statement, the data first received from the channel will be printed out.
12.1 Buffered channel
Buffered channels can be created in Golang, and when buffer s are full, sending data to channel will be blocked. For example:
package main import "fmt" func main() { ch := make(chan string, 2) ch <- "hello" ch <- "world" ch <- "!" // extra message in buffer fmt.Println(<-ch) } // => fatal error: all goroutines are asleep - deadlock!
Why is Golang so successful?
Simple...
- Rob-pike
13. Summary
We learn the following main modules and features of Golang:
- List items
- Variables, data types
- Array, Slices and Map
- function
- Loop and conditional statements
- Pointer
- package
- Methods, Structures and Interfaces
- error handling
- Concurrency -- Go routines and channels
Congratulations, you have a good understanding of Go.
One of my most productive days was throwing away 1,000 lines of code.
- Ken Thompson
Don't stop and move on. Think about a small application and get started.
Links to the original text:
Originality: Milap Neupane High Availability Architecture
https://mp.weixin.qq.com/s?__...
https://milapneupane.com.np/2...
Milap Neupane, the author of this article, was translated by He Pengpeng. If you reprint this article, please indicate the source. More small partners are welcome to join the ranks of translators and contributors. For details, please stamp the public number menu "Contact us".