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