@[toc]

Hello, everyone! I am clean!

Part 1: Kick you in the door of GO!

Ⅰ, the foundation is not strong, the earth is shaking

1. First example: Hello World

package main
import "fmt"
func main(){
    fmt.Println("Hello World")
}

The first line, package main, represents which package the current file belongs to. Package is the keyword for the Go life package, main is the package name, and the main package is a special package that represents the project as a running application, rather than as a library referenced by other projects.

The second line import “FMT” imports an FMT package, import is the keyword

The third line func main(){} defines a function. Func is the keyword, main is the name of the function, and mian is a special function that represents the entry point to the entire program. When the program runs, main is called.

The fourth line, fmt.println (“Hello World”), prints the “Hello World” text through the FMT package’s Println function.

2.Go environment construction

From the website https://golang.org/dl/ website (abroad) and https://golang.google.cn/dl/ (domestic website) to download the Go language development kit.

2.1 Environment Variables

  • GoPath: The working directory of the Go project, which now has the Go Module mode, is basically used to hold the project retrieved using the Go Get command
  • Gobin: Go compiles the generated program installation directory, such asgo installThe command installs the generated Go program into the GOBIN directory for use by the terminal.
  1. If the working directory is /Users/wucs/go, you need to set the GOPATH environment variable to /Users/wucs/go and the GOBIN environment variable to $GOPATH/bin
  2. For Linux/ MacOS, add the following to /etc/profile or $HOME/.profile to save:

    export GOPATH=/Users/wucs/go
    export GOBIN=$GOPATH/bin

3. Project structure

We started development with the Go Module mode, which does not require code to be placed in the GoPath directory and allows projects to be created anywhere.

  1. For example, if the project location is \golang\gotour, open the terminal, switch to the project directory, and execute Go mod init example.com/hello, a go.mod file will be generated. Then create a main.go file in the root of the project.

    Go Mod is an official package dependency management tool introduced in Golang 1.11. It is designed to solve the problem of not having a place to record the specific version of a dependency package.

    • Go mod init "module name"Initialize the module.
    • go mod tidyAdd missing packages and remove unused packages
  1. Writes the Hello World instance at the beginning of the article to the main.go file.

    Main. go is the entry file for the entire project, which contains the mian function.

4. Compile and publish

  1. Execute in the project root directorygo build ./main.goThe main.exe file is generated in the project root directory
  2. In the project root directory, terminal inputmainEnter successfully to print “Hello World”, indicating that the program ran successfully.
  3. The executable file generated above is in the root of the project. You can also install it in the $GOBIN directory or anywhere else:

    go install /main.go

    The go install command generates the program in the $GOBIN directory. You can now open the terminal anywhere, type mian enter, and it will print “Hello World”.

5. Cross-platform compilation

What is cross-platform compilation? For example, if you’re developing under Windows, you can compile programs that run on Linux.

The Go language controls cross-platform compilation through two environment variables, GOOS and GOARCH.

  • Goos: Represents the target operating system to compile. Common ones include Linux, Windows, Darwin, etc.
  • Goarch: Represent the target processor architecture to compile. Common examples include 386, AMD64, ARM64, etc
GOOS= Linux GOARCH= AMD64 go build./main.go

For more combinations of GOOS and GOARCH, see the $GOOS and $GOARCH section of the official documentation.

Ⅱ, data type

1. What types do they have

Variable declarations

  1. Var variable name type = expression

    var i int = 10
  2. Type inference

    var i = 10

    Variable types can be omitted based on the type of the value
  3. Declare multiple variables

    Var (I = 0, k = 1) var (I = 0, k = 1)

    Basic types such as int/float64/bool/string can be derived automatically.

    #### Integers In Go, integers are divided into:

    • Signed integers: int, int8, int16, int32, int64
    • Unsigned integers: uint, uint8, uint16, uint32, uint64

      Note:

      1. Signed integers can represent negative, zero, and positive numbers, while unsigned integers can represent only zero and positive numbers.
      2. The int and uint types have no specific bit size. They can be 32bit or 64bit, depending on the CPU of the hardware device.
      3. In integers, the explicit int type is used if the bit of an int can be determined, which helps portability of the program.
      4. There is also a byte type called byte, which is equivalent to UINT8. It can be understood as an alias for the type UINT8, and is used to define a single byte.

    # # # # floating point number Is containing the decimal floating point Numbers, the language provides two precision floating-point number: float32, float64. Float64 is more commonly used because of its high accuracy and less error in floating-point calculations than in floats.

    # # # # the Boolean

    • There are only two types of Boolean values: true and false.
    • Defining uses:var bf bool = false; useboolKeyword definition

    #### String String is declared as the type String

    Var s1 string = "hello" var s2 = "world" var s3 = s1 + s2 // You can concatenate strings with the + operator s1 += s2 // You can also operate with the += operator

    #### Null value Null value is the default value of a variable. In Go, if a variable is declared and no value is assigned to it, the variable will have a corresponding type of zero value.

    Var b bool // bool is false


    Var s string // string zero is “”


    The following six types of zero-valued constants are nil


    var a *int


    var a []int


    var a map[string] int


    var a chan int


    var a func(string) int


    Var an error // error is the interface

2. A short declaration of variables

In real projects, short declarations are used most often when they can be initialized for declared variables.

Pointer to 3.

In the Go language, a pointer corresponds to the location of a variable in memory, which means that the value of the pointer is the memory address to traverse. The & allows you to get the address of the variable, which is the pointer. * You can get the value of the address.

pi:=&i
fmt.Println(*pi)

4. Constant

Constant values are determined at compile time and cannot be changed to prevent malicious tampering at run time.

Constants defined

And variable types, but with the keyword const

Const name = "dust-free"

In the Go language, only basic types such as booleans, strings, and numbers are allowed as constants.

5.iota

IOTA is a constant generator that can be used to initialize constants of similar rules, avoiding repeated initializations.

// const (one = iota+1 two three) const (one = iota+1 two three)

The initial value of IOTA is 0.

6. The string

  1. Strings and numbers are interchanged

Go is a strongly typed language, and variables of different types cannot be used and evaluated against each other. Variables of different types need to be cast before they are copied or computed.

i := 10
itos := strconv.Itoa(i)
stoi,err := strconv.Atoi(itos)
fmt.Println(itos,stoi,err) //10 10 nil
  1. The String bag

The string package is a standard package provided with the Go SDK. Toolkit for handling strings. Contains finding a string, splitting a string, removing whitespace from a string, and determining whether a string contains a prefix or suffix.

// If the prefix of s1 is H FMT.Println(Strings.HasPrefix(s1,"H")) // Look for the string o FMT.Println(Strings.Index(s1,"o")) // uppercase s1 fmt.Println(strings.ToUpper(s1))

See the String documentation for more examples

Ⅲ, Control structure

1. If statement

func main() {
    i:=6
    if i >10 {
        fmt.Println("i>10")
    } else if i>5 && i<=10 {
        fmt.Println("5<i<=10")
    } else {
        fmt.Println("i<=5")
    }
}

Note:

  1. The expression after if does not have ‘()’.
  2. The ‘{}’ in each conditional branch is required. Even if it’s just one line of code. 3. ‘{‘ after if/else cannot monopolize a line. Otherwise the compile will not pass

2. Switch select statement

The if conditional statement works well when there are fewer branches. If there are many branches, the switch is more convenient.

switch i:=6; { case i > 10: fmt.Println("i>10") case i > 6 && i <= 10: fmt.Println("5<i<10") default: fmt.Println("i<=5") }

Note: In order to avoid forgetting to write the break, Go language has a break after the case, which is different from other languages.

If you do need to execute the next case, you can use the fallthrough keyword

switch j:=1; J {case 1: fallthrough case 2: FMT.Println("1") default: FMT.Println(" no match ")}

The result above will print 1.

When an expression follows a switch, the value after the case must be of the same type as the result of the expression. For example, j is of type int, so the value after the case must be of type int.

3. For loop statements

The for loop consists of three parts, two of which need to be used; Segmentation:

sum := 0
for i := 1; i <= 100; i++{
  sum += i
}
fmt.Println("sum:",sum)

The first part is a simple statement


The second part is the condition of the for loop


The third part is the update statement


None of these three components are required and can be omitted.

There is no while loop in Go. We can use for to achieve the effect of while:

sum := 0
i := 1
for i <= 100 {
  sum += 1
  i++
}

In Go, continue and break control for loops are also supported.

  1. Continue out of the loop and into the next loop.
  2. Break forces the exit from the loop.

Ⅳ, the collection type

1. Array

Arrays hold fixed – length data of the same type.

1.1 Array Declaration

  1. Var < array name > = [< length >]< element >{element 1, element 2}

    Var arr = [2] int {1, 2}

    or

    The arr: [2] = int {1, 2}
  2. Var < array name > = […] < element type >{element 1, element 2}

    var arr = [...] Int. {1, 2}

    or

    arr := [...] Int. {1, 2}
  3. Var < array name > = […] < type >{index 1: element 1, index 2: element 2}

    `var arr = […] Int {1:1, 0-2}

    `

    or

    arr := [...] Int {1:1, 0-2}

Each element of the array is stored contiguously in memory, and each element has a subscript starting at 0.


The array length can be omitted and is automatically deduced from the elements in {}.


There is no initialized index. The default value is zero of the array type.

1.2 Array Loop

For I,v := range array {fmt.printf (" index :%d, value :% s\n", I,v)}
  1. The range expression returns the array index assigned to I and the array value assigned to v.
  2. If the value returned is not needed, we can discard it with _ underscore:

    For _,v:= range array{fmt.printf (" %s\n", I,v)}

2. Slice

Slice and array types, can be understood as dynamic array, slice is based on the implementation of array, its bottom is an array. Splitting an array gives you a slice.

2.1 Array generation slice

slice := array[start:end]

array := [5]string{"a","b","c","d","e"}
slice := array[2:5]
fmt.Println(slice) //[c d e]

Note: This contains index 2, but does not contain index 5 elements, namely: closed left, open right.


After sectioning, the index range of the sectioning is also changed.


Array [start:end] : array[start:end] : array[start:end] : array[start:end] : array

Array [:] is equivalent to array[0:5]

2.2 Section modification

The value of the slice can also be modified, and here it can also be proved that the underlying slice is an array.

array := [5]string{"a","b","c","d","e"}
slice := array[2:5] //[c d e]
slice[1] = "f"
fmt.Println(slice) //[c f e]
fmt.Println(array) //[a b c f e]

If the slice is modified, the corresponding array value is also modified. Therefore, it is proved that the underlying array is still the original array used in the arraion-based slice. Once the element value of the slice is modified, the corresponding value of the underlying array will also be modified.

2.3 Section declaration

Declare slices using the make function

Slice1 := make([]srting,4,8) slice1 := make([]srting,4,8) slice1 := make([]srting,4,8)

The volume of the slice cannot be smaller than the length of the slice.


Length is just the number of elements.


Volume is the space of the slice.

The example above has a memory space of 8, but only 4 memory Spaces are used, the rest of the memory space is free. When an element is appended to a slice via append, it is appended to free memory, and when there is not enough space left, it is expanded.

Literals initialize slices

slice2 := []string{"a","b","c"}
fmt.Println(len(slice2),cap(slice2)) //3 3

2.3 Append

The append function appends an element to a slice:

Slice3 := append(slice2,"d","f") slice3 := append(slice2,"d","f")

Tip:


When creating a new slice, it is best to have the same length as the size, so that the append operation will generate a new underlying array, which will be separated from the existing array, so that the contents of the common underlying array will not be affected by the change of the contents of multiple slices.

2.4 Sectioning cycle

Slice loops, like arrays, use the for range mode.

3. A Map is a Map.

Map is an unordered set of k-v key-value pairs. Where k must be of the same type. K and V can be of different types. The type of k must support the == comparison operator so that it can be determined to exist and guaranteed to be unique.

3.1 Map declaration initialization

  1. make:

    mapName := make(map[string]int)
  2. Literal:

    MapName := map[String]int{MapName := map[String]int{MapName := map[String]

If you don’t want to add a key-value pair to your creation, use empty braces {}, but don’t omit them.

3.2 Map acquisition and deletion

// select * from mysql. id where mysql. id = mysql. id where mysql. id = mysql. id where mysql. id = mysql. id = mysql. id where mysql. id = mysql. id

If the key does not exist, the value returned is the zero value of the key. Therefore, in many cases, it is necessary to determine whether the key in the map exists or not.

NameAge := make([string]int) nameAge[" clean "]=29 age,ok := nameAge[" clean "] if ok {fmt.println (age)}
  • Map’s [] operation returns two values

    • The first one is value
    • The second is to mark whether the key exists. If it does, it will be true

The delete() function

Delete (nameAge, "clean")

  • Delete takes two parameters, a map and a key to delete.

4. The traverse Map

NameAge [" clean "] = 29 nameAge[" clean 1"] = 30 nameAge[" clean 2"] = 31 for k,v := range nameAge{FMT.Println("key is",k,"value is ",v) }
  • Corresponding to map,for range returns two parameters, k and v.

Tip: When traversing a map, for range uses a return value, which is the key of the map.

4.1 Map size

A map is different from a slice in that it has only length, not volume. You can use the len function to get the map size.

5. The String and byte []

A string is also an immutable sequence of bytes that can be converted directly to a byte slice []byte:

B := []byte(s) b := []byte(s)

Not only can a string be converted directly to a []byte, but you can also use the [] operator to retrieve the byte value of the specified index.

Strings are sequences of bytes, one byte per index, and three bytes per Chinese character in UTF8 encoding.


To calculate a character as a length, use the utf8.runeCountinString function.


For range is a loop of Unicode characters, one character for one length.

Ⅴ, functions, and methods

1. The function

1.1 Function declaration

func funcName(params) result {
  body
}
  • The keyword func is used to declare a function
  • FuncName function name
  • Parameter to the params function
  • Result is the return value of a function. You can return more than one return value; if none, you can omit it.
  • The body function body

Example 1.

  • A and B parameters have the same type. You can omit the declaration of one of the types

    func sum (a, b int) {
    return a + b
    }

2. Multiple returns

  • Part of the type definition for the return value needs to be enclosed in parentheses.

    Func sum (int a, b) (int, error) {if a < 0 | | b < 0 {return 0, errors. The New (" a or b can't be negative ")} return a + b, nil}

3. Named parameters are returned

  • If a named return parameter is assigned to a function, it is the same as if the function had a return value, so you can ignore the value returned after the return.

    func sum (a, b int) (sum int,err error) { if a <0 || b <0 { return 0, Errors. New(" A or B cannot be negative ")} sum = a + b err = nil return}

    4. Variable parameters

  • The arguments to the function are variable
  • To define mutable parameters, simply add three dots before the parameter type… Can be
  • The type of a mutable parameter is actually a slice. In the example below, the parameter type of params is []int

    func sum(params ... int) int { sum := 0 for _, i := range params { sum += i } return sum }

1.2 Package-level functions

  • Each function belongs to a package. Our custom function belongs to the main package. The Println function belongs to the FMT package.
  • To call a function from another package, the name of that function should be capitalized to make its scope public.
  • Functions with a lowercase initial can only be called in the same package

1.3 Anonymous Functions and Closures

An anonymous function is one that has no name.

Func main(){sum := func(a, b int) int {return a + b} FMT.Println(sum(1, 2)) // 3}

An anonymous function can be nested within a function, called an inner function. An inner function can use variables from an outer function. This is called closure.

func main (){ sm := sum() fmt.Println(sum()) fmt.Println(sum()) fmt.Println(sum()) } func sum () func() int{ i := 0 Return func ()int{I ++ return I}} //

Because of the closure function, the sum function returns an anonymous function that holds the variable I of the external function sum, so in main, every time sum() is called, the value of I is +1.

In the Go language, a function is also a type, which can be a variable of a function type, a parameter, or the return value of a function.

Method 2.

A method is similar to a function except that it must have a receiver, which is a “class” (type), so that the method belongs to that class.

type Name string
func (n Name)String(){
  fmt.Println("name is ", n)
}
  • In the example, String() is a method of type Name
  • The receiver needs to be inserted between the func and method name, using ().
  • Receiver: (variable, type)

Use:

Func main(){name := name (" clean ") name.string ()

3. Value type receivers, pointer type receivers

The receiver of the method can use either the value type (as in the above example) or the pointer type. If the receiver is a pointer, then the change to the pointer is valid:

Func (n *Name) Modify(){*n = Name("wucs")} func main(){Name := Name(" clean ") name.string () name.string ()} // output name is clean name is wucs

Note: When a method is called, the receivers passed are essentially copies of each other, except that one is a copy of the value and one points to this
The value of the pointerA copy of. The pointer points to the original value, so changing the value to which the pointer points changes the original value.


The caller of the method, either a value or a pointer ((&name).modify ()), is escaped by the Go language and we don’t need to worry about it.

4. Method expressions

Methods can be assigned to variables

Name := name (" clean ") // Assign the method to the variable, the method expression n = name.string // To pass a receiver name to call n(name)

Whether a method has arguments or not, by calling a method expression, the first argument must be the receiver, followed by the arguments to the method itself.

Ⅵ, struct, and interface

1. The structure

1.1 define

A struct is an aggregate type. It can contain any type of value, either as a member of the struct or as a field. To define a struct, use the type+struct keyword

Type person struct {// Person struct name string // Person struct age uint // Person struct age uint}
  1. Type and struct are keywords that define the type of a new structure.
  2. Person is the name of the structure.
  3. Name /age is the name of the field of the structure, followed by the corresponding field type.
  • A field declaration is similar to a variable in that the variable name comes first and the type comes second
  • The field can be a person, a field without a structure, become an empty structure.
  • A struct is also a type. For example, the Person struct means the same thing as the Person type.

1.2 the statement

  1. Initialize var p person as a normal string, integer hospital declaration

    A variable p of type Person is declared, but is not initialized, so the default value of the field in the structure is zero.

  2. P := person{” clean “,18}

    The name field representing the structure variable p is initialized to “clean” and the age field is initialized to 18. The order must be the same as the order in which the fields are defined.

  3. P := person{age:18,name:” dust-free “}

    By pointing out the field names like this, you can shuffle the order in which the fields are initialized. You can also initialize only some of the fields and default to zero for the rest of the fields:
    p := person{age:30}

1.3 Field structure

Structure fields can be of any type, including custom structure types:

Type person struct {// name string age uint addr address // use custom struct} type address struct {// city string address}

For such nested structures, the initialization is similar to that of a normal structure. The field is initialized according to the type of the field:

P := person {age:18, name:" clean ", addr:address{city:" Beijing ",},}

The fields of a structure use the dot operator, just as they do when calling a method of a type. :

Println(p.age) // To access the value of the city field in the nested structure: FMT.Println(p.addr.city)

2. The interface

2.1 define

An interface is an abstract type, a contract with the caller. An interface just needs to define conventions that tell the user what to do without knowing its internal implementation. The definition of the interface is the Type + Interface keyword class implementation.

GetInfo () String type Info interface {getInfo () String type Info interface}

Correspondingly, the Stringer interface tells the caller that a String can be retrieved from a String(), which is the interface’s convention. How the String is retrieved does not matter to the interface, nor does the caller, since it is up to the implementer of the interface to handle it.

2.2 Implementation of interface

The implementer of the interface must be of a specific type:

func (p person) Getinfo() string {
  return fmt.Sprintf("my name is %s,age is %d",p.name,p.age)
} 
  • The struct Person implements the Info interface by defining a method that has the same name, parameters, and return value as the method in the interface.
  • If an interface has more than one method, the interface is not implemented until all the methods in the interface are implemented.

2.3 the use of

Let’s first define a function that prints the Info interface:

func printInfo(i Info) {
  fmt.Println(i.Getinfo())
}
  • Define the function PringInfo, which takes an argument of the Info interface type, and then prints the string returned by the getInfo method of the interface.
  • This is a program to an interface, the pringInfo function only any type implements the Info interface, this function can be used to print out the corresponding string, and don’t care about the specific type.

    PrintInfo (p) // The result is: my name is clean,age is 18

    Because the Person type implements the Info interface, the variable p can be used as an argument to the function printInfo.

3. Value receiver, pointer receiver

  1. To implement an interface, you must implement all the methods in the interface.
  2. Define a method that has a value type receiver and a pointer type receiver, both of which can call the method because the Go compiler does the conversion automatically.
  3. But the implementation of the interface is different for value type receivers and pointer type receivers

The above interface body Person implements the Info interface. Does the structure pointer implement that interface as well?

printInfo(&p)

The test found that a pointer to p also works well as a parameter function, indicating that the interface is implemented as a value type receiver, and that both the type itself and the pointer type of the type implement the interface

So change the receiver to a pointer type:

func (p *person) Getinfo() string {
    return fmt.Sprintf("my name is %s,age is %d",p.name,p.age)
}

This is followed by a call to printInfo(p), which fails to compile, indicating that the interface is implemented as a pointer receiver. Only the corresponding pointer type is considered to have implemented the interface

Method receiver Implementation interface type
(p person) The person and person
(p * person) *person
  • Both the Person type and * Person type implement the interface when the value type is the receiver.
  • When the pointer type is the receiver, only the * Person type implements the interface.

Ⅶ, error handling, error, and panic

1. Error

In the Go language, errors are not very serious, they are expected, and can be returned to the caller to handle themselves.

1.1 the error interface

In Go, errors are represented by the built-in error interface, which has only one error method to return the error message:

type error interface {
  Error() string
}

Here is an example of an error:

func main() { i,err := strconv.Atoi("a") if err ! = nil { fmt.Println(err) }else { fmt.Println(i) } }
  • The example intentionally uses the wrong string “a” to convert to an integer, so an error message is printed here:

    strconv.Atoi: parsing "a": invalid syntax
  • In general, the Error interface returns when a function or method invocation encounters an error and is the second return value so that the caller can handle the error himself.

1.2 Error factory function

We can use the errors.New factory function to generate error messages, which takes a string argument and returns an Error interface.

Func test(m,n int) (int, error) {if m > n {return m,errors.New("m greater than n")}else {return n,nil}}

When m is about n, an error message is returned.

1.3 Custom Error

The factory function above can only pass a string to return. To carry more information, you can use a custom error:

Type testError struct {errorCode int // errorMsg string // Error message} func (t *testError) Error() string{return t.errorMsg }

Here’s a custom error, which can return more information:

Return m, &testError{errorCode: 1, errorMsg: "m > n"}

This is returned by creating * TestError as a literal.

1.4 the error assertion

An error assertion can convert the Error interface to its own error type:

Res, err := test(2,1) if e,ok := test(*testError); Println(" error code: ", e.rrormsg,", error message: ", e.rrormsg)} else {fmt.println (res)}

2. Panic abnormalities

Go is a static language, and many errors can be caught at compile time, but the panic exception is only thrown at run time for things like array access out of line and casts of different types. We can also throw a panic exception manually. For example, we can connect to a MySQL database:

Func connectMySQL(IP,username,password string){if IP =="" {panic(" IP cannot be empty ")} // omit other code}
  • In the above function, the Panic exception is thrown if the IP address is empty.
  • Panic is a built-in function that accepts arguments of type interface{}. This means that any value can be passed to Panic:

    func panic(v interface{})

    Interface {} represents an empty interface, representing any type.


    Panic is a very serious error that causes a program to stop execution, so
    If it is not an error that affects the execution of the program, use Error

2.1 Recover capture Panic exception

Normally we do not handle panic exceptions, but if there are some operations that need to be handled before the program crashes, you can use the built-in recover function to recover panic exceptions. When Panic crashes, only the deferred decorated function is executed, so the recover function is used in conjunction with the defer keyword:

func main() { defer func() { if p:=recover(); p! =nil{ fmt.Println(p) } }() connectMySQL("","root","123456") }

Recover catches the panic exception and prints: ‘Recover returns the value of the parameter passed through the panic function. IP cannot be empty

  • The return value of the recover function is the value passed by the panic function.
  • The function decorated with the defer keyword is executed before the main function exits.

Ⅷ, assertions, and reflection

1. Interface assertion

Speaking of interface assertions, let’s review how to implement interfaces.

  • The implementer of the interface must be a concrete type
  • The method name, parameters, and return value of the method defined by the type must be the same as in the interface
  • If the interface has multiple methods, implement all the methods in the interface

For the empty interface{}, since it does not define any functions (methods), all types in Go implement the empty interface.

When a function’s parameter is interface{}, it means that the parameter is automatically converted to type interface{}. In the function, if you want to obtain the actual type of the parameter, you need to assert the parameter.

  • Type assertion converts the value X of the interface type to the value T of the format X.(T).
  • Type assertion X must be of interface type
  • T can be a non-interface type, and for an assertion to be valid, T must implement X’s interface

1.1 Syntax format:

/ / not safety type asserts that "the value of the target type > : = > < expressions. (the target type) / / safety type asserts that" the value of the target type >, < > Boolean parameters: = > < expressions. (the target type)

The sample

package main import "fmt" func whoAmi(a interface{}) { //1. Cannot convert a (type interface{}) to type string: need type assertion // fmt.println (string(A)) //2. // FMT.Println(a.(string)) // dust-free //3. Value, ok := a.(string) // Security, the assertion fails, there is no panic, just ok is false if! Return} FMT.Println(value) // clean} func main() {STR := "clean" whoAmi(STR)}

Another form of assertion is to use the switch statement to determine the type of the interface:

func whoAmi(a interface{}) {
    switch a.(type) {
    case bool:
        fmt.Printf("boolean: %t\n", a) // a has type bool
    case int:
        fmt.Printf("integer: %d\n", a) // a has type int
    case string:
        fmt.Printf("string: %s\n", a) // a has type string
    default:
    fmt.Printf("unexpected type %T", a) // %T prints whatever type a has
    }
}

2. The reflection

The Go language provides a mechanism that can be used at runtime
Update and check the value of the variable, the method by which the variable is called, and the intrinsic operations that the variable supports, but in
The exact types of these variables are not known at compile timeThis mechanism is called reflection.

2.1 What is the use of reflection

  • Above we mentioned the empty interface, which can receive anything
  • But how do you know what type an empty interface variable stores? The type assertions described above can be implemented
  • You need to use reflection if you want to get the type and value information of the stored variable
  • Reflection is the mechanism by which variable type and value information can be dynamically retrieved

2.1 reflect bag

Reflection is supported by the Reflect package, which provides two types of access to the contents of interface variables, namely Type and Value. The Reflect package provides two functions to get the Type and Value of any object:

  1. func TypeOf(i interface{}) Type
  2. func ValueOf(i interface{}) Value
function role
reflect.TypeOf() Gets the type information of the variable, and returns it if it is emptynil
reflect.ValueOf() Gets the value of the data, and returns it if it is null0

Example:

Package main import (" FMT ""reflect") func main() {var name string =" FMT "// TypeOf returns the TypeOf the variable, ReflectType := reflect.typeof (name) // valueOf returns the valueOf the variable, reflectType := reflect.typeof (name) // valueOf returns the valueOf the variable ReflectValue := reflect.valueOf (name) fmt.println ("type: ", reflectValue) //type: string fmt.println ("value: ", reflectValue) //type: string fmt.println ("value: ", reflectValue) ", reflectValue) //value: micro-guest bird nest}
  1. Reflect. Type is actually an interface that defines a number of methods for retrieving type-related information:

    Int Align() int int int int int int int int int int int int int FieldAlign() int // Returns the 'I' (passed in) Method in the Method set Method(int) Method // Returns the 'I' (passed in) Method by name (String) (Method, String); Bool) / / type method were obtained in the export of NumMethod method number (int) / / type Name Name () the string / / the return type of the path, such as: Encoding /base64 PkgPath() string encoding/base64 PkgPath() string Unsafe. Sizeof function similar to Size() uintptr // return type String() String // return type Kind() Kind // Whether the type Implements the interface u Implements(u Type = u AssignableTo(u Type) bool // Type = u ConvertibleTo(u Type) bool // Type = u ConvertibleTo(u Type) bool // Type = u Comparable() Bool // The following functions can be called only of certain types: }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} Can only be func type call / / t is func (int x, y... // then t.sVariadic () == true isVariadic () bool // returns the type of the inner child, // If I is greater than the total number of fields in a struct, the number of fields in a struct is greater than the total number of fields in a struct. Panic Field(I int) structField // Returns the Field fieldByIndex (index []int) structField for the nested structure // Gets the Field fieldByName (name) by the Field name string) (StructField, FieldByNameFunc returns FieldByNameFunc(match func(string)) // FieldByNameFunc returns the struct field with a name Bool) (structField, bool) In(I int) Type In(I int) Type (Key() Type); (Len() int); (Len() int); NumField() int can only be called from a Struct of type numField () int // NumIn() int // NumOut() int // NumOut() int can only be called from a Struct of type numField () int Common () *rtype uncommonType} is too small to be common() as well as uncommonType}.
  2. The reflect.Value returned by the function TypeOf is a struct type. The Value structure defines a number of methods by which you can directly manipulate the actual data pointed to by the Value field PTR:

    // Set the len field of the slice. If the type is not slice, Panic func (v Value) SetLen(n int) // Set cap field of slice func (v Value) SetCap(n int) // Set dictionary's kv func (v Value) SetMapIndex(key, Val Value) // return the Value at I func (v Value) Index(I int) Value String) Value / /...

    Struct reflection example:

    package main import ( "fmt" "reflect" ) type Address struct { City string } type Person struct { Name string Age uint Address (p Person) Hello(){fmt.println (" I'm clean ")} func main() {//p := Person{Name:" clean ",Age:18,Address:Address{City:" Beijing "}} // Map Assign p := Person{" clean ",18,Address{" Beijing "}} // Get the target object t := Reflect.typeof (p) fmt.println ("t:", t) //.name () T Name()) // Get the target object's value type v: = reflect.valueOf (p) fmt.println ("v:", v) //.numField () Get the total number of fields it contains for I := 0; i < t.NumField(); I ++ {// get the key in Person from 0 key := t.field (I) // value := v.field (I).interface () Fmt.printf (" The %d field is: %s:%v = %v \n", I +1, key.name, key.type, value)} fmt.printf ("%#v\n", t.fieldByIndex ([]int{2, 0})) //.numMethod () to get the method in Person for I :=0; i<t.NumMethod(); I++ {m: = t.M ethod FMT. (I) Printf (" % d method is: % s: % v \ n ", I + 1, m.N ame, m. ype)}}

    Running results:

    Person v: Person v: Person v: Person v: Person Name:string = Age:uint = 18 Age:uint = 18 Age:uint = 18 Age:uint = 18 Address: main.address = {Beijing} reflect.structfield {Name:"City", PkgPath:"", Type:(*reflect.rtype)(0x4cfe60), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:false} Hello:func(main.person)
  3. Modify the content by reflection

    Package main import ("reflect" "FMT") type Person struct {Name string Age int} func main() {p := &person {" clean ",18} v := reflect.valueOf (p) // Change value must be of pointer type if v.IND ()! = reflect.ptr {fmt.println (" non-pointer type, ") return} // get the Value of the target key name := v.fieldByName (" name ") if name.kind () == reflect.String { name.SetString("wucs") } fmt.Printf("%#v \n", *p) // test := 666 testV := reflect.valueOf (&test) testv.elem ().setInt (999) fmt.println (test)}

    Running results:

    main.Person{Name:"wucs", Age:18} 
    999
  4. Methods are called through reflection

    package main import ( "fmt" "reflect" ) type Person struct { Name string Age int } func (p Person) EchoName(name String){fmt.println (" My name is: ", name)} func main() {p := Person{name: "dustless ",Age: 18} v := reflect.valueOf (p) // Get control of the method // Returns the Value of the binding (holding Value to V) state of the method named name of V in function form encapsulated mv := v.MethodByName("EchoName") // piecing parameter args := [] reflect.value {reflect.valueOf ("wucs")} // Call mv.call (args)}

    Running results:

    My name is: Wucs

Part 2: An example of efficient concurrent programming for Go

  • This is an introduction to the basics of Go programming. The next section will cover concurrent programming later. Thank you for watching.
  • Welcome message exchange, correct
  • My wx: wucs_dd, public number “micro guest bird’s nest”, focus on GO development technology sharing.