[GO Language Fundamentals] GO functions, packages and error mechanisms (7)

Go file structure and escape characters

//输出hello world 
pacakage main //归属包路径

import "fmt" //引入包

func main () { //main函数
    fmt.Println("hello world!") //每句结尾可省略“;”
    fmt.Println("hello world!"); fmt.Println("hello world!")//go是一行行编译执行的,所以尽量不要把多条=语句写在同一行,如果你打算将多个语句写在同一行,则必须使用 ; 人为区分,但在实际开发中我们并不鼓励这种做法。
    /*
    转义字符:
        \a             匹配响铃符    (相当于 \x07)
                    注意:正则表达式中不能使用 \b 匹配退格符,因为 \b 被用来匹配单词边界,
                    可以使用 \x08 表示退格符。
        \f             匹配换页符    (相当于 \x0C)
        \t             匹配横向制表符(相当于 \x09)
        \n             匹配换行符    (相当于 \x0A)
        \r             匹配回车符    (相当于 \x0D) 
        \v             匹配纵向制表符(相当于 \x0B)
        \123           匹配 8  進制编码所代表的字符(必须是 3 位数字)
        \x7F           匹配 16 進制编码所代表的字符(必须是 3 位数字)
        \x{10FFFF}     匹配 16 進制编码所代表的字符(最大值 10FFFF  )
        \Q...\E        匹配 \Q 和 \E 之间的文本,忽略文本中的正则语法

        \\             匹配字符 \
        \^             匹配字符 ^
        \$             匹配字符 $
        \.             匹配字符 .
        \*             匹配字符 *
        \+             匹配字符 +
        \?             匹配字符 ?
        \{             匹配字符 {
        \}             匹配字符 }
        \(             匹配字符 (
        \)             匹配字符 )
        \[             匹配字符 [
        \]             匹配字符 ]
        \|             匹配字符 |
    */
    fmt.Println("hello\rworld!")
}

Factory mode

Golang's structure has no constructor, and the factory pattern can usually be used to solve this problem.

    结构体变量首字母大写,引入后,直接当作构造函数使用:
    type Student struct{
        Name string
        score float64
    }
    type student struct{
        Name string
        score float64
    }

    //因为student结构体首字母是小写,因此是只能在model使用
    //我们通过工厂模式来解决
    func NewStudent(n string, s float64) *student {
        return &student{
            Name : n,
            score : s,
        }
    }

    //如果score字段首字母小写,则,在其它包不可以直接方法,我们可以提供一个方法
    func (s *student) GetScore() float64{
        return s.score //ok
    }

function

A collection of program instructions (statements) for accomplishing a certain function is called a function.
In Go, functions are divided into: custom functions, system functions

The Go language function definition format is as follows:

func function_name ([parameter list]) [return_types] {
    //函数体
}

Function definition analysis:

  • func: The function is declared by func
  • function_name: function name, function name and parameter list together constitute the function signature.
  • parameter list: A parameter list. The parameter is like a placeholder. When the function is called, you can pass the value to the parameter. This value is called the actual parameter. The parameter list specifies the parameter type, order, and number of parameters. Parameters are optional, which means that the function does not need to contain parameters.
  • return_types: return type, the function returns a list of values. return_types is the data type of the column value. Some functions do not require a return value, in this case return_types is not necessary.
  • Function body: The code collection of the function definition.

Function call mechanism:

Basic data types are generally allocated to the stack area, and the compiler has escape analysis.
Reference data types are generally allocated to the heap area, and the compiler has escape analysis.

  1. When a function is called, a new space will be allocated to the function, and the compiler will distinguish this new space from other stack spaces through its own processing
  2. In the stack corresponding to each function, the data space is independent and will not be confused
  3. When a function is called (executed), the program will destroy the stack space corresponding to this function.

Function return value

The Go function can return multiple values. If you want to ignore a return value when receiving, use the _ symbol to indicate that the placeholder is ignored

Recursive function call

A function calls itself in the function body, we call it recursive call

  1. When a function is executed, a new protected independent space (new function stack) is created
  2. The local variables of the function are independent and will not affect each other
  3. Recursion must approach the condition of exiting recursion, otherwise it will be infinite recursion, dead turtle :)
  4. When a function is executed, or when it encounters return, it will return. Whoever calls it will return the result to whoever. At the same time, when the function is executed or returns, the function itself will also be destroyed by the system.

Notes and detailed discussion

  • There can be multiple function parameter lists and multiple return value lists.

  • The data types of the formal parameter list and the return value list can be value types and reference types.

  • The naming of the function follows the identifier naming convention. The first letter cannot be a number, and the first letter is capitalized. This function can be used by this package file and other package files, similar to public, with the first letter lowercased, and can only be used by this package file, but not other package files. Use, similar to privat

  • Variables in the function are local and do not take effect outside the function

  • Basic data types and arrays are passed by value by default, that is, value copy is performed. Modifications within the function will not affect the original value.

  • If you want the variables in the function to modify the variables outside the function (referring to the data type that is passed by value by default), you can pass in the address of the variable &, and manipulate the variable in the function as a pointer. Seen from the effect, it is similar to the reference.

  • Go functions do not support function overloading

  • In Go, a function is also a data type, which can be assigned to a variable, then the variable is a variable of the function type. This variable can be used to call the function

  • Since the function is a data type, in Go, the function can be used as a formal parameter and called

  • In order to simplify the definition of data types, Go supports custom data types

  • Support naming function return values

  • Use the _ identifier, ignore the return value

  • Go supports variable parameters

        func sum (args... int) sun int {
            //支持0到多个参数
        }
    
        func sum (n1 int, args... int) sun int {
            //支持1到多个参数
        }
    
        说明:
        (1)args是slice切片,通过args[index] 可以访问到多个值
        (2)如果一个函数的形参列表中有可变参数,则可变参数需要放在形参列表最后
    
  • init function
    Each source file can contain an init function, which will be called by the Go framework before the main function is executed, which means that init will be called before the main function.

  1. If a file contains global variable definition, function and main function at the same time, init will execute the process global variable definition ->init function ->main function
  2. The main function of the init function is to complete some initialization work
  3. If both the main package and the reference package contain variable definitions, during the init function, the execution process refers to the package variable definition -> reference package init function -> main package variable definition -> main package init function -> main package main function
  • Anonymous functions
    Go supports anonymous functions. An anonymous function is a function without a name. If we only want to use a function once, we can consider using an anonymous function. An anonymous function can also be called multiple times.

Usage 1
is called directly when the anonymous function is defined. In this way, the anonymous function can only be called once.
```
func main () { res := func (n1 int, n2 int) { return n1+n2 } (10, 20) fmt.Println(res) }




    //结果
    30
```

Use method 2
Assign an anonymous function to a variable (function variable), and then use the variable to call the anonymous function
```
a := func (n1 int, n2 int) int { return n1-n2 }

    res := a(90, 30)
    fmt.Println(res)

    //结果
    60
```

Global anonymous function: If an anonymous function is assigned to a global variable, then this anonymous function becomes a global anonymous function, which can be effective in the program.

package

The essence of the package is actually to create different folders to store program files.
Every file in go belongs to a package, which means go manages files and project directory structure in the form of a package

Three functions of the package

  • Distinguish identifiers such as functions and variables with the same name
  • When there are many program files, the project can be managed well
  • Control the access scope of functions, variables, etc., that is, scope

Basic syntax for packaging

    package 包名

The basic syntax of the imported package

    import "包的路径"

Precautions

  1. When packaging a file, the package corresponds to a folder. For example, the package name corresponding to the utils folder here is utils. The package name of the file is usually the same as the name of the folder where the file is located, usually in lowercase letters.

  2. When a file needs to use other package functions or variables, the corresponding package needs to be introduced first

    • Introduction method 1:

          import "包名"
      
      
    • Introduction method 2:

          import (
              "包名"
              "包名"
          )
      
      
    • The package instruction is on the first line of the file, followed by the import instruction.

    • When importing the package, the path starts under src under $GOPATH, without src, the compiler will automatically import it from under src

  3. In order to allow files in other packages to access the functions of this package, the first letter of the function name needs to be capitalized, similar to public in other languages, so that it can be accessed across packages. For example, utils.go

  4. When accessing other package functions and variables, the syntax is package name.function name, such as in the main.go file here

  5. If the package name is long, Go supports aliasing the package. Pay attention to the details: After aliasing, the original package name cannot be used.
    Note: If you alias the package, you need to use the alias to access the package's functions and variables.

  6. In the same package, there cannot be the same function name (nor the same global variable name), otherwise it will report a duplicate definition

  7. If you want to compile into an executable program file, you need to declare the package as main, which is package main. This is a grammar specification. If you are writing a library, the package name can be customized

Closure

  • The concept of closure:

It is a code block that can contain free (not bound to a specific object) variables. These variables are not defined in this code block or in any global context, but are defined in the environment where the code block is defined. The code block to be executed (because the free variables are contained in the code block, these free variables and the objects they refer to are not released) provide a binding computing environment (scope) for the free variables.

  • The value of closure:

The value of closures is that they can be used as function objects or anonymous functions. For the type system, this means not only data but also code. Most languages ​​that support closures treat functions as first-level objects, which means that these functions can be stored in variables and passed to other functions as parameters. The most important thing is that they can be dynamically created and returned by the function.

Closures in Go also refer to variables outside of functions. The implementation of closures ensures that as long as the closure is still used, the variables referenced by the closure will always exist.

    //累加器
    func AddUpper() func (int) int {
        var n int = 10 
        var str = "hello"
        return func (x int) int {
            n = n + x
            return n
        }
    }

    func main() {
        //使用前面的代码
        f := AddUpper()
        fmt.Println(f(1))// 11 
        fmt.Println(f(2))// 13
        fmt.Println(f(3))// 16
    }


  • to sum up:

Closures are not an indispensable function of a programming language, but the manifestations of closures generally appear in the form of anonymous functions. As mentioned above, they can be dynamically and flexibly created and transferred, reflecting the characteristics of functional programming. . Therefore, in some occasions, we have an additional choice of coding methods, and proper use of closures can make our code concise and efficient.

  • Points to note when using closures

Since the closure will make the variables in the function be stored in memory, the memory consumption is very large, so the closure cannot be abused

defer

In functions, programmers often need to create resources (such as database connections, file handles, locks, etc.). In order to release resources in time after the function is executed, the designer of Go provides defer (delay mechanism).

   代码:
    func sum(n1 int, n2 int) int {
        
        //当执行到defer时,暂时不执行,会将defer后面的语句压入到独立的栈(defer栈)
        //当函数执行完毕后,再从defer栈,按照先入后出的方式出栈,执行
        defer fmt.Println("ok1 n1=", n1) //defer 3. ok1 n1 = 10
        defer fmt.Println("ok2 n2=", n2) //defer 2. ok2 n2= 20
        //增加一句话
        n1++ // n1 = 11
        n2++ // n2 = 21
        res := n1 + n2 // res = 32
        fmt.Println("ok3 res=", res) // 1. ok3 res= 32
        return res

    }

    func main() {
        res := sum(10, 20)
        fmt.Println("res=", res)  // 4. res= 32
    }


    输出结果:
    ok3 res = 30
    ok2 n2 = 20
    ok1 n1 = 10
    res = 30



  • Notes and details
  1. When go executes to a defer, the statement after defer is not executed immediately, but the statement after defer is pushed onto a stack, and then the next statement of the function is executed.
  2. When the function is executed, in the defer stack, the statements are taken out from the top of the stack in turn for execution (note: follow the stack first-in-last-out mechanism),
  3. When defer puts the statement on the stack, the related value will be copied and put on the stack at the same time.
  • Description:
  1. The usual practice in golang programming is to create a resource, such as (open a file, get a database link, or lock a resource), you can execute defer file.Close() defer connect.Close()
  2. After defer, you can continue to use the creation resource.
  3. When the function is completed, the system will take out the statements from the defer stack in turn, and close the resources.
  4. This mechanism is very concise, and programmers no longer need to worry about when to close resources.

Parameter passing method

  • Two delivery methods
  1. Pass by value
  2. Pass by reference
    In fact, whether it is passed by value or by reference, what is passed to the function is a copy of the variable. The difference is that the value passed is a copy of the value, and the reference passed is a copy of the address. Generally speaking, the address copy is efficient. , Because the amount of data is small, and the value copy determines the size of the data copied, the larger the data, the lower the efficiency.
  • Value type and reference type
  1. Value types: basic data types int series, float series, bool, string, array and structure struct
  2. Reference type: pointer, slice slice, map, pipe chan, interface, etc. are all reference types
  • Characteristics of the use of value passing and reference passing
  1. The default value type is value transfer: variables store the value directly, and memory is usually allocated on the stack
  2. The reference type is passed by reference by default. Variables store an address. The space corresponding to this address actually stores the data (value). The memory is usually allocated on the heap. When any variable references this address, the data space corresponding to the address It becomes a garbage and is collected by the GC.
  3. If you want the variables in the function to modify the variables outside the function, you can pass in the address of the variable &, and manipulate the variables in the function as a pointer. Seen from the effect, it is similar to the reference.

Variable scope

  1. The variables declared/defined inside the function are called local variables, and the scope is limited to the function
  2. The variables declared/defined outside the function are called global variables, and the scope is valid in the entire package. If the first letter is capitalized, the scope is valid in the entire program
  3. If the variable is in a code block, such as for / if, then the scope of the variable is in the code block

Commonly used system functions for strings

  1. Count the length of the string, in bytes len(str)
  2. String traversal, while dealing with Chinese problems r := []rune(str)
  3. String to integer: n, err := strconv.Atoi("12")
  4. Integer to string str = strconv.Itoa(12345)
  5. String to []byte: var bytes = []byte("hello go")
  6. []byte to string: str = string([]byte{97, 98, 99})
  7. Decimal to 2, 8, hexadecimal: str = strconv.FormatInt(123, 2) // 2-> 8, 16
  8. Find if the substring is in the specified string: strings.Contains("seafood", "foo") //true
  9. Counting a string has several specified substrings: strings.Count("ceheese", "e") //4
  10. Case-insensitive string comparison (== is case-sensitive): fmt.Println(strings.EqualFold("abc","Abc")) // true
  11. Returns the index value of the first occurrence of the substring in the string, if it does not return -1: strings.Index(“NLT_abc”, “abc”) // 4
  12. Returns the index of the last occurrence of the substring in the string, if it does not return -1: strings.LastIndex("go golang", "go")
  13. Replace the specified substring with another substring: strings.Replace("go go hello", "go", "go language", n) n can specify how many you want to replace, if n=-1 means replace all
  14. According to a specified character, split a string into a string array for the split identification: strings.Split("hello,wrold,ok", ",")
  15. Convert the letters of a string to case: strings.ToLower(“Go”) // go strings.ToUpper(“Go”) // GO
  16. Remove the spaces on the left and right sides of the string: strings.TrimSpace(" tn a lone gopher ntrn ")
  17. Remove the specified characters on the left and right sides of the string: strings.Trim("! hello! ", "!") //Remove the left and right sides! and" "// ["hello"]
  18. Remove the specified characters on the left side of the string: strings.TrimLeft("! hello! ", "!") //Remove the left side! and" "// ["hello"]
  19. Remove the specified characters on the right side of the string: strings.TrimRight("! hello! ", "!") //Remove the right side! and" "// ["hello"]
  20. Determine whether the string starts with the specified string: strings.HasPrefix("ftp://192.168.10.1", "ftp") // true
  21. Determine whether the string ends with the specified string: strings.HasSuffix(“NLT_abc.jpg”, “abc”) //false

Time and date related functions

  1. Time and date related functions, need to import the time package
  2. time.Time type, used to represent time
  3. Get date information
	//看看日期和时间相关函数和方法使用
	//1. 获取当前时间
	now := time.Now()
	fmt.Printf("now=%v now type=%T\n", now, now)

	//2.通过now可以获取到年月日,时分秒
	fmt.Printf("年=%v\n", now.Year())
	fmt.Printf("月=%v\n", now.Month())
	fmt.Printf("月=%v\n", int(now.Month()))
	fmt.Printf("日=%v\n", now.Day())
	fmt.Printf("时=%v\n", now.Hour())
	fmt.Printf("分=%v\n", now.Minute())
	fmt.Printf("秒=%v\n", now.Second())

  1. Format date and time
  • Method 1: Use Printf or SPrintf
	fmt.Printf("当前年月日 %d-%d-%d %d:%d:%d \n", now.Year(), 
	now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())

	dateStr := fmt.Sprintf("当前年月日 %d-%d-%d %d:%d:%d \n", now.Year(), 
	now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())

	fmt.Printf("dateStr=%v\n", dateStr)

  • Method 2: Use the time.Format() method to complete:
    //Format根据layout指定的格式返回t代表的时间点的格式化文本表示。
    //layout定义了参考时间:2006年1月2日15时04分05秒是Go语言诞生的日子 
    //记忆方法:6-1-2-3-4-5
	fmt.Printf(now.Format("2006-01-02 15:04:05"))
	fmt.Println()
	fmt.Printf(now.Format("2006-01-02"))
	fmt.Println()
	fmt.Printf(now.Format("15:04:05"))
	fmt.Println()
	fmt.Printf(now.Format("2006"))
	fmt.Println()

  1. The constant
    time is composed of:

time.Duration (length of time, time consumed)
time.Time (point in time) time.C (
channel channel for playing time) (Note: Time.C:=make(chan time.Time))

    const (
        Nanosecond    Duration = 1 //纳秒
        Microsecond = 1000 * Nanosecond //微秒
        Millisecond = 1000 * Microsecond //毫秒
        Second = 1000 * Millisecond //秒
        Minute = 60 * Second //分钟
        Hour = 60 * Minute //小时
    )

    常量的作用:在程序中可用于获取指定时间单位的时间,比如想得到 100 毫秒
    100 * time. Millisecond


  1. Dormant
	time.Sleep(time.Second)
	time.Sleep(time.Millisecond * 100)

  1. Unix timestamp and UnixNano timestamp method of time
  • Unix expresses t as Unix time, that is, the elapsed time (in seconds) from January 1, 1970 UTC to time t.
  • UnixNano represents t as Unix time, that is, the elapsed time from January 1, 1970 UTC to time t (in nanoseconds)
    fmt.Printf("unix时间戳=%v unixnano时间戳=%v\n", now.Unix(), now.UnixNano())

Error mechanism

By default, when an error occurs (panic), the program will exit (crash). Go language pursues simplicity and elegance, so Go language does not support the traditional try...catch...finally processing. The processing methods introduced in Go are: defer , panic , recover

A panic exception can be thrown in Go, and then the exception can be caught by recover in defer, and then processed normally

    func test() {
        //使用defer + recover 来捕获和处理异常
        defer func() {
            err := recover()  // recover()内置函数,可以捕获到异常
            if err != nil {  // 说明捕获到错误
                fmt.Println("err=", err)
                //处理异常
            }
        }()
        num1 := 10
        num2 := 0
        res := num1 / num2
        fmt.Println("res=", res)
    }

After error handling, the program will not hang up easily. If the warning code is added, the program can be made more robust.

Custom exception

In Go programs, custom errors are also supported, using errors.New and panic built-in functions.

  1. errors.New("error description"), will return a value of type error, indicating an error
  2. The panic built-in function receives an interface{} type value (that is, any value) as a parameter. You can receive variables of type error, output error messages, and exit the program.
    //函数去读取以配置文件init.conf的信息
    //如果文件名传入不正确,我们就返回一个自定义的异常
    func readConf(name string) (err error) {
        if name == "config.ini" {
            //读取...
            return nil
        } else {
            //返回一个自定义异常
            return errors.New("readConf Exception..")
        }
    }

    func main() {
        err := readConf("config2.ini")
        if err != nil {
            //如果读取文件发送错误,就输出这个错误,并终止程序
            panic(err)
        }
        fmt.Println("test02()继续执行....")  //异常退出后 不会执行
    }

Guess you like

Origin blog.csdn.net/weixin_54707168/article/details/113977656