Go language Bible - Chapter 5 - 5.5 function values

Keywords: Go Back-end Functional Programming

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.5 function value

Function values are assigned to variables

In Go, functions are regarded as the first type of values: functions, like other values, have types, can be assigned to other variables, pass functions, and return from functions. Calls to function values are similar to calls to functions

func square(n int) int     { return n * n }
func negative(n int) int   { return -n }
func product(m, n int) int { return m * n }
func main() {
   f := square // In essence, the function is changed to a new name, which can be used in future calls
   fmt.Println(f(3))//9
   g := negative //(type is func(int) int)
   fmt.Println(g(3))//-3
   fmt.Printf("%T\n",g)//func(int) int type is actually the keyword func + (parameter type) + return value type
}

The zero value of a function type is equal to nil, which is the same as the zero value of an int type is equal to 0. Calling will cause panic because many function types are the same. We directly declare and call this way, and the compiler does not know which function we want to execute

var h func(int)int
fmt.Println(h(i))//Because the above function type is nil, it cannot be called directly. In fact, it is impossible to declare a function type variable in the above way

Function values can be compared with nil and

var h func(int)int
if h == nil {
   fmt.Println("panic occurs")
}

However, function values cannot be compared, and function values cannot be used as the key of a map

Function as parameter

func add1(r rune) rune {return r+1}

fmt.Println(strings.Map(add1,"HAL-9000")) //IBM.:111
fmt.Println(strings.Map(add1,"VMS")) //WNT
fmt.Println(strings.Map(add1,"Admix")) //Benjy

Of course, it can also be operated by assigning the function value to a new variable and then calling it

j := add1
fmt.Println(strings.Map(j,"HAL-9000")) //IBM.:111
fmt.Println(strings.Map(j,"VMS")) //WNT
fmt.Println(strings.Map(j,"Admix")) //Benjy

We continue to look at the function value. The findLinks function in Section 5.2 uses the auxiliary function visit to traverse and operate all nodes of the HTML page

However, if the function value is used in this link, we can separate the logic of traversing the node from the logic of operating the node, so that we can reuse the traversal logic and perform different operations on the node

func ForEachNode(n *html.Node, pre, post func(n *html.Node)) {
   if pre != nil {
      pre(n)
   }
   for c := n.FirstChild; c != nil; c = c.NextSibling {
      ForEachNode(c, pre, post)
   }
   if post != nil {
      post(n)
   }
}

We see that the function receives two functions as parameters (pre,post), which are called before and after the access of the node child. This design gives the caller great flexibility. For example:

Now we have endElement and start functions to output the start tag and end tag of HTML elements...:

var depth int
func startElement(n *html.Node) {
   if n.Type == html.ElementNode {
      fmt.Printf("%*s<%s>\n",depth*2,n.Data)
      depth ++
   }
}
func endElement(n *html.Node) {
   if n.Type == html.ElementNode {
      depth --
      fmt.Printf("%*s</%s>\n",depth*2,n.Data)
   }
}

The above code uses a trick of fmt.Printf to control the indentation of the output. In% s, some spaces will be filled in front of the string. In the example, each output will first fill in the number of spaces of depth*2, then output "", and finally output HTML tags

If we call forEachNode like this

ForEachNode(doc,startElement,endElement)

Compared with the previous outline program, we will get a more detailed page structure

Posted by defunct on Tue, 02 Nov 2021 18:08:14 -0700