Chapter 5 functions
Function allows us to package a statement sequence into a unit, and then call it many times from other parts of the program. The mechanism of function allows us to decompose a large work into small tasks. We have touched on functions before, and we will discuss more features of functions in this chapter
5.3 multiple return values
We all know that a function can have multiple return values. Next, let's continue to study the return values of functions
There are generally two function return values in many annotation libraries, one is the expected return value, and the other is the error message when the function fails
Let's take a look at the newly rewritten findlinks function. The newly modified findlinks can initiate HTTP requests by itself. Because both HTTP requests and parsing operations may fail, the findlinks function has two return values, each of which displays the link list and the other returns an error message
Generally speaking, the HTML parser can handle the error nodes of HTML pages and construct the HTML page structure, so parsing HTML rarely fails, which means that if findlinks fails, it is likely to be caused by I/O errors
func main() { for _, url := range os.Args[1:] { links,err := findlinks(url) if err != nil { fmt.Fprintf(os.Stderr,"findlinks2",err) continue } for _,link := range links { fmt.Println(link) } } } func findlinks(url string) ([]string,error) { resp,err := http.Get(url) if err != nil { return nil,err } if resp.StatusCode != http.StatusOK { resp.Body.Close() if err != nil { return nil, fmt.Errorf("getting %s: %s", url,resp.Status) } } doc, err:= html.Parse(resp.Body) resp.Body.Close() if err != nil { return nil,fmt.Errorf("parising %s as HTML :%v",url,err) } return visit(nil,doc),nil }
In findlinks, there are four return statements. The first three times return error information, and the second and third times use fmt.Errof to output detailed error information. If findlinks ends successfully, the last set of parsed links is returned to the user
In findlinks, we must ensure that resp.Body is closed to release network resources. Although Go's garbage collection mechanism will recycle unused memory, it does not include operating system level resources, such as open files and network connections. Therefore, we must explicitly release these resources
The caller must explicitly assign multiple return values of a function to a variable
links, err := findLinks(url)
Within a function, another function call with multiple return values can be used as the return value. The return value types of the two functions are the same
func findLinkslog(url string)([]string, error) { log.Printf("findlinks %s", url) return findlinks(url) }
Of course, a function parameter can also be the return value of another function
log.Println(findlinks(url)) links,err := findlinks(url) log.Println(links,err)
The exact variable name can convey the meaning of the return value of the function
func Size(rect image.Rectangle)(width,height int) func Split(path string)(dir,file string) func HourMinsec(t time.Time)(hour,minute,second int)
Although accurate naming is very important, there is no need to ask for an appropriate name for each return value, especially for some habitual return values, such as bool for success or not
If all the return values of a function have explicit variable names, the return statement can omit the operands and call it bare return
func CountWordsAndImages(url string)(words,images int,err error){ resp,err := http.Get(url) if err != nil { return } doc,err := html.Parse(resp.Body) resp.Body.Close() if err != nil { err = fmt.Errorf("parsing HTML :%s",err) return } words,images = countWordsAndImages(doc) return } func countWordsAndImages(n *html.Node) (words,images int){/*...*/}
Each return statement in the above code is equivalent to
return words, images, err
When a function returns multiple times, bare return can reduce the amount of code. This point should be conscious before the function is constructed, so as to decide whether to explicitly declare the return value. However, it should also be noted that Go initializes the return value to 0 at the beginning of the function body according to their type, so the first two returns are equivalent to the first two returns, equivalent to return 0,0,err, and the last return is equivalent to return words, image, nil. For this reason, we should not use bare return excessively