Go Language for an article (typesetting)

Posted by Nabster on Mon, 29 Jul 2019 07:08:26 +0200

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".

Topics: Go JSON Programming Google