Golang Understanding - Anonymous Functions

Anonymous function

Anonymous Function in computer programming refers to a class of functions that need not be defined. identifier (function name) function or subroutine It exists in many programming languages. wikipedia

Golang supports anonymous functions, that is, when a function is needed, it is redefined. Anonymous functions have no function name, only function body. Functions can be assigned to variables of function type as a type. Anonymous functions are often passed by variables.

Anonymous functions are often used to implement callback functions, closures, etc.

Definition of anonymous function

Anonymous functions are defined as ordinary functions without names.

func (parameter list) (return value list){
    Function Body
}

Call of anonymous functions

1 Call anonymous functions at definition time

Anonymous functions can be called directly after declaration; for example:

package main

import "fmt"

func main() {
    // Define anonymous functions and assign them to f variables
    f := func(data int) {
      fmt.Println("hello", data)
    }
  // In this case, the type of f variable is func(), which can be called directly.
    f(100)
}

Anonymous functions are widely used. Anonymous functions themselves are a kind of value, which can be conveniently stored in various containers to realize callback functions and operation encapsulation.

2 Anonymous function as callback function

Callback function, or call back for short, is called by the main function and returns to the main function after the operation is called by the main function. Functional parameters A block passed to another code. Executable code Of Quote

The design of anonymous functions as callback functions is very common in go language system packages, which are implemented in strings packages.

func TrimFunc(s string, f func(rune) bool) string {
        return TrimRightFunc(TrimLeftFunc(s, f), f)
}

Let's write a demo to understand the characteristics of callback function.

package main

import "fmt"

/*
    Objectives:
        For slice traversal operation, the operation of accessing each element in traversal is implemented by anonymous function. 
        Users can traverse elements by passing in different anonymous function bodies.
*/

// Traversing through each element in the slice, accessing elements through a given function
func visit(list []int, f func(int)) {
    for _, value := range list {
        f(value)
    }
} 

func main() {
    l := []int{1,2,3}
    // Print the contents of the slice using anonymous functions
    visit(l, func(value int) {
        fmt.Println(value)
    })
}

Encapsulation of anonymous functions

Encapsulation refers to a kind of encapsulation. abstract The method of encapsulating and hiding the details of the implementation of sexual function interface. At the same time, it is also a way to prevent external callers from accessing it. object The internal implementation details are provided by the programming language itself.

The following code regards anonymous function as the key value of map and dynamically calls anonymous function through command function parameters.

package main

import (
    "fmt"
    "flag"
)


// Resolve parameters passed in from the command line using the flag package
// The parameters parsed in the flag package are pointer variables of type * string, which can not be called directly when the value is invoked.
var skillParm = flag.String("skill", "", "skill to perform")

func main() {
    // Parse parameters; after parsing, skillParm will execute the values passed in from the command line
    flag.Parse()

    // Define a map of a string mapped to func(), and then fill in the map
    var skill = map[string]func(){
      "fire": func(){
          fmt.Println("chicken fire")
      },
      "run": func() {
          fmt.Println("soldier run")
      },
      "fly": func(){
          fmt.Println("angle fly")
      },
    }
    // If the incoming value exists, the value of the map (where the value is an anonymous function) is called for printing.
    if f, ok := skill[*skillParm]; ok {
            f()
    } else {
            fmt.Println("skill not found")
    }

}

Function Implementation Interface

Interface is widely used in go language. There is a saying in Jianghu that "go is Interface-oriented programming". What if we use functions to achieve the same function as interface?

Functions, like other types, belong to "first-class citizens". Other types can implement interfaces, and functions can also be implemented.

Let's compare the similarities and differences between functions and structured entities in implementing interfaces:

1 Architecture Implementation Interface

The function we want to implement is that this interface needs to implement the Call() method, and the call will pass in a variable of interface {} type, which represents any type of value.

package main

import (
    "fmt"
)

// Caller interface, defines an interface, implements the Call() method
type Invoker interface{
        Call(interface{})
}

// Define the type of structure without defining any member and can receive any type of data
type Struct struct{}

// Call Method for Implementing Invoker
func (s *Struct) Call(p interface{}) {
        fmt.Println("from struct", p)
}

func main() {
    // Declare interface variables, instantiate the defined Struct type, and pass it into the interface for invocation
    var invoker Invoker

    // Example speech structure
    s := new(Struct)  // <==> s := &Struct

    // Assigning instantiated constructs to interfaces
    invoker = s

    // Call the Strct.Call() method, which instantiates the structure, using the interface
    invoker.Call("hello")
}

2 Function Implementation Interface

Function Implementation Interface: Function declaration can not directly implement the interface. After defining the function as a type, we need to use the type to implement the structure. When the type method is called, we also need to call the function ontology.

package main

import (
    "fmt"
)

// Caller interface
type Invoker interface{
        Call(interface{})
}

// Functions are defined as types, and func(interface {}) is defined as FuncCaller type. 
// In this paper, the function type is defined, and the function itself needs to be processed logically. 
// FuncCaller does not need to be instantiated, just converts functions to FuncCaller types.
// Function sources can be named functions, anonymous functions, or closures
type FuncCaller func(interface{})

// Call Method for Implementing Invoker
func (f FuncCaller) Call(p interface{}) {
    // Calling the function ontology, FuncCaller's All () method is called regardless of func(interface {}).
    // You also need to call the function ontology manually
    f(p)
}
func main(){
    // Declare interface variables
    var invoker Invoker

    // Convert an anonymous function to a FuncCaller type and assign it to the interface
    invoker = FuncCaller(func(v interface{}) {
      fmt.Println("from function", v)
    })

    // Call FuncCaller.Call with the interface and call the function ontology internally
    invoker.Call("hello")
}

Examples in system packages

In the Go language, some packages of the system also use functions to implement interfaces, such as HTTP packages that have examples of functions to implement interfaces.

HTTP package contains Handler interface definition, code as follows:

type Handler interface {
        ServeHTTP(Response Writer, *Request)
}

Handler is used to define each http request and the corresponding processing process. At the same time, it can also use the processing function to implement the interface, which is defined as follows:

type HandlerFunc func(ResponseWriter, *Request)

func(f HandlerFunc) ServeHTTP(W ResponseWriter, r *Request) {
        f(w, r)
}

To implement default HTTP request processing using closures, you can use the http.HandleFunc() function, which is defined as follows:

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        DefaultServeMux.HandleFunc(pattern, handler)
}

DefaultServeMux is a ServeMux structure with HandlerFunc() method. DefaultServeMux is defined as follows:

func (mux *ServeMux) HandlerFunc(pattern string, handler func(ResponseWriter, *Request)) {
        mux.Handler(pattern, HandlerFunc(handler))
}

The above code converts the external function handler() to HandlerFunc type, which implements the Serve HTTP method of Handler. The bottom layer can use various types to implement Handler interface for processing at the same time.

Reference resources

Go Language from Introduction to Advanced Practice-Xu Bo

Keywords: PHP Programming Go

Added by leena on Sun, 21 Jul 2019 16:49:12 +0300