The fifth chapter go language Bible (study notes)

The fifth chapter function

Function declarations

  • There is no default parameter values
  • Argument passed by value, the parameter is a copy of the argument
  • When the argument is a reference type (pointer, slice, map, function, channel, etc.), the argument may be modified
  • You may experience no function declaration function body, which means that the function is not implemented Go, for example,
package math
func Sin(x float64) float //implemented in assembly language

Recursion

  • Most of the programming language function call stack using a fixed size, ranging from 64KB to lay a common 2MB. However, Go uses a variable stack, which allows us to not have to consider when using recursion overflow and safety issues

Multi return value

error

  • Go in error handling, will return an error message when the program fails, it is the expected result rather than an exception
  • When the error is only one reason, use a Boolean value, usually named ok on it
  • When there are many reasons for the error, you need to know more information about the error, error type will be used
  • Built-in error is the interface type, its non-nil or is nil

Error handling strategy

  • Error propagation: a function routine fails, the failure of the function becomes
    1. Error message format may be used fmt.Errorf
    2. Error messages are often grouped together in a chain, so that the error message should be avoided upper and newline
    3. when writing an error message, make sure that the error message description of the problem to be exhaustive detail
  • Chance Error: If an error occurs incidental, or unexpected problems caused
    1. retry the failed operation (limit retry interval or the number of retries to prevent unlimited retries)
  • Can not run Error: If an error occurs, the program can not continue to run
    1. output an error message and end the program (this strategy is performed only in main)
    2. For library functions should only propagate upward wrong
    3. If the error means internal program contains inconsistencies that met bug, to end the program in a library function
// (In function main.)
if err := WaitForServer(url); err != nil {
    fmt.Fprintf(os.Stderr, "Site is down: %v\n", err)
    os.Exit(1)
}

4. wording or more concise (equivalent to the above example)

if err := WaitForServer(url); err != nil {
    log.Fatalf("Site is down: %v\n", err)
}
  • No effect of error: error messages output just enough, without interrupting the operation of the program
//log包中的所有函数会为没有换行符的字符串增加换行符
if err := Ping(); err != nil {
    log.Printf("ping failed: %v; networking disabled",err)
}
if err := Ping(); err != nil {
    fmt.Fprintf(os.Stderr, "ping failed: %v; networking disabled\n", err)
}
  • You can ignore the error: we can ignore the error directly
dir, err := ioutil.TempDir("", "scratch")
if err != nil {
    return fmt.Errorf("failed to create temp dir: %v",err)
}
// ...use temp dir...
os.RemoveAll(dir) // ignore errors; $TMPDIR is cleaned periodically
  • Error handling Recommended Style:
    1. checking whether a sub-function fails, we usually deal with the failure of logic code in the code before processing was successful.
    2. If the function returns an error will result, when the logic of the code should not be placed successfully in else block, but should be placed directly in the function body
    3. In other words, the first series of initial check, prevent errors occurs, then the actual logic function

End of file error (EOF)

  • io ensure that any package by the end of the file read failed due to return the same error: io.EOF
package io
import "errors"
// EOF is the error returned by Read when no more input is available.
var EOF = errors.New("EOF")

Function value

  • In Go, the function value is regarded as a first category (first-class values): Like other values ​​as a function, with the type, can be assigned to other variables, passed to the function, the function returns from
func square(n int) int { return n * n }
func negative(n int) int { return -n }
func product(m, n int) int { return m * n }
f := square
fmt.Println(f(3)) // "9"
f = negative
fmt.Println(f(3))
// "-3"
fmt.Printf("%T\n", f) // "func(int) int"
f = product // compile error: can't assign func(int, int) int to func(int) int

var f func(int) int
f(3) // 此处f的值为nil, 会引起panic错误
//还可以和nil比较,但函数值之间不可比较
if f != nil {
    f(3)
}

Anonymous functions (anonymous function)

strings.Map(func(r rune) rune { return r + 1 }, "HAL-9000")
// squares返回一个匿名函数。
// 该匿名函数每次被调用时都会返回下一个数的平方。
func squares() func() int {
    var x int
    return func() int {
        x++ //访问到这个函数定义的变量!
        return x * x
    }
}
func main() {
    f := squares()
    fmt.Println(f()) // "1"
    fmt.Println(f()) // "4"
    fmt.Println(f()) // "9"
    fmt.Println(f()) // "16"
}
  • Function value is not a string of codes, also recorded state. In the above example, the return value FUNC squares () can access and update the x, which means that anonymous functions and squares, there is a reference variable (reference value belongs to the function type and function reasons not comparable)
  • go use closures (Closures) technology function value, the function value is usually referred to as closure
  • When the anonymous function recursively, you declare a variable
func main() {
    for i, course := range topoSort(prereqs) {
        fmt.Printf("%d:\t%s\n", i+1, course)
    }
}
func topoSort(m map[string][]string) []string {
    var order []string
    seen := make(map[string]bool)
    var visitAll func(items []string)
    visitAll = func(items []string) {
        for _, item := range items {
            if !seen[item] {
            seen[item] = true
            visitAll(m[item])
            order = append(order, item)
            }
        }
    }
    var keys []string
    for key := range m {
        keys = append(keys, key)
    }
    sort.Strings(keys)
    visitAll(keys)
    return order
}

Warning: Capture iteration variable

  • Promising practices:
var rmdirs []func()
for _, d := range tempDirs() {
    dir := d // NOTE: necessary!
    os.MkdirAll(dir, 0755) // creates parent directories too
    rmdirs = append(rmdirs, func() {
        os.RemoveAll(dir)
    })
}
// ...do some work...
for _, rmdir := range rmdirs {
    rmdir() // clean up
}
  • Viable option:
var rmdirs []func()
for _, dir := range tempDirs() {
    os.MkdirAll(dir, 0755)
    rmdirs = append(rmdirs, func() {
        os.RemoveAll(dir) // NOTE: incorrect!
    })
}
  • The scope of the problem is the loop variable.
    1.for lexical cycle introduces new block, the loop variable is declared in this dir lexical block
    all function values generated in the cycle 2 are sharing the same loop variable
    3. function values recorded in the memory address of the loop variable rather than the value of the loop variable at a time

variable parameter

  • When you declare a variable parameters need to add ...
func sum(vals...int) int {
    total := 0
    for _, val := range vals {
        total += val
    }
    return total
}

func main() {
    fmt.Println(sum()) // "0"
    fmt.Println(sum(3)) // "3"
    fmt.Println(sum(1, 2, 3, 4)) // "10"
}
  • Obviously, the above example is treated as vals..int [] int processed
  • sum (1,2,3,4) implicitly create an array, the array as a parameter sliced, passed sum

Deferred function

  • Defer the use of keywords, with the subsequent function will be delayed execution:
    1. defer up to and including the statement of a function is finished, the function is performed only after the defer statement,
    2. Prior to this matter again whether a return or panic
    3 . defer statement may be performed in a plurality of function execution order and the reverse order of their statement
    4. defer statement in the loop body only after the function is finished, the delay function is performed only
for _, filename := range filenames {
    f, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer f.Close() // NOTE: risky; could run out of file
    descriptors
    // ...process f...
}

5. The method of solution is to move to another function defer

for _, filename := range filenames {
    if err := doFile(filename); err != nil {
        return err
    }
}
func doFile(filename string) error {
    f, err := os.Open(filename)
    if err != nil {
        return err
    }
    defer f.Close()
    // ...process f...
}

Panic abnormal

  • Run-time checking, error is caused by an abnormal panic
  • In general, after the panic occurred program will interrupt the operation and execution of the goroutine defer immediately after the program crashes and output log information
  • Log information includes stack trace information panic value and function calls
  • Can be artificially triggered panic (used only in very serious mistake): Use the built-in panic function
  • runtime stack information output packet allows programmers
gopl.io/ch5/defer2
func main() {
    defer printStack()
    f(3)
}
func printStack() {
    var buf [4096]byte
    n := runtime.Stack(buf[:], false)
    os.Stdout.Write(buf[:n])
}

Recover catch the exception

  • "For example, when a web server encountered an unexpected serious problems in the collapse
    should close all connections before the collapse; if no treatment, will make the client has been in a wait state if the web.
    Server is still in development the server can even abnormal feedback to the client, to help debugging. "
  • "If you call built-in functions recover the deferred function, and define the function statement defer occurred panic different
    often, the program will recover recover from panic and returns panic value"
  • "Causing panic abnormal function does not continue to run
    the line, but can return to normal. Call recover when panic does not occur, recover returns nil"
func Parse(input string) (s *Syntax, err error) {
    defer func() {
        if p := recover(); p != nil {
            err = fmt.Errorf("internal error: %v", p)
        }
    }()
    // ...parser...
}

Guess you like

Origin www.cnblogs.com/laiyuanjing/p/11229141.html