Core: The function is first-class citizen

Simple log printing scenario

type User struct {
	Name   string
	Age    int
}

func main() {
	user := &User{Name: "Jack", Age: 18}
	log.Printf("debug level. user:%v\n",user)
}
Copy the code

Json.marshal () should be used first for each scenario, assuming that different scenarios require different log formats. For example, scenarios A,B, and C require JSON. The following

func main() {
	user := &User{Name: "Jack", Age: 18}
	s, _ := json.Marshal(user)
	log.Printf("user:%v\n",string(s))
}
Copy the code

There is an object-oriented approach, where the User implements a JsonString() method. But today, I’m going to do func

First-class citizen func to do something

So let’s write a function like this

func Debug(user *User) {
	s, _ := json.Marshal(user)
	log.Printf("debug level. user:%v\n",string(s))
}
Copy the code

Instead of calling the Debug method directly, you define another function, a list of parameters that can hold the Debug function, as follows

type User struct {
	Name   string
	Age    int
}

func LogUserData(user *User, fun func(u *User)) {
	fun(user)
}
func main() {
	user := &User{Name: "Jack", Age: 18}
	LogUserData(user,DebugJson)
}

func DebugJson(user *User) {
	s, _ := json.Marshal(user)
	log.Printf("debug level. user:%v\n",string(s))
}
Copy the code

One advantage of this is that the framework for logging printing is defined, leaving the details of logging printing externally, thus ensuring the ability to extend changes. Second, if all log printing needs to add some common pre – or post-actions, you can add them to LogUserData, so as to avoid the repeated work of adding pre – and post-conditions in various scenarios by directly calling the DebugJson method. In addition, if different action implementation details have different pre – or post-actions, they can be added in the action implementation function. For example, I need to add an Error level log printing method, and the Error log needs SMS to inform me of the Error of the system, so I can directly expand it

Func LogUserData(user * user, fun func(u * user)) {"Start printing log") fun(user) // common after log.printf ("Log printing completed")} func Error(user * user) {// special prefix // send SMSdo Something...
	log.Printf("error level. user:%v\n",user)
}
Copy the code

Second, fun’s parameter list doesn’t have to be the same as User’s, as long as it has some relevance, such as redefining a function that judges minors

func IsAdult(user *User, fun func(age int) bool )bool {
	return fun(user.Age)
}
func main() {
	user := &User{Name: "Jack", Age: 18}
	b := IsAdult(user, JudgeAdult)
	fmt.Println(b)
}
func JudgeAdult(age int) bool {
	if age >= 18 {
		return true
	}
	return false
}
Copy the code

conclusion

The method above is called func(body obj, action func), also known as FUNC (message obj, message consumption action func), which I call a consumption function, and is widely used in Golang, such as NET/HTTP

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

The main approach is to use a framework function called func that takes the body, and then receives the action that acts on the body, and uses that action to do some kind of processing on the body. That’s what it looks like graphically

Golang Net/HTTP HandleFunc, for example, defines only the framework for sending and receiving HTTP requests, leaving it up to the outside world to define how to handle requests and what to respond to.

In fact, this is the idea of section. In a process, the main body and the processing process of the main body are cut off, and the processing process is handed over to the external implementation, so that the process has higher flexibility and expansibility.

Attach all code

package main

import (
	"encoding/json"
	"log"
	"fmt"
)

typeFunc LogUserData(User *User, fun func(u *User)) {log.printf (struct {Name string Age int})"Start printing log") fun(user) // common after log.printf ("Log printing completed"} // adult (user * user, fun func(age int) bool)bool {adult (user * user, fun func(age int) bool)boolreturn fun(user.Age)
}
func main() {
	user := &User{Name: "Jack", Age: 18}
	LogUserData(user,DebugJson)
	LogUserData(user,Info)
	LogUserData(user,Error)
	b := IsAdult(user, JudgeAdult)
	fmt.Println(b)
}
func JudgeAdult(age int) bool {
	if age >= 18 {
		return true
	}
	return false
}
func DebugJson(user *User) {
	s, _ := json.Marshal(user)
	log.Printf("debug level. user:%v\n", string(s))
}
func Info(user *User) {
	log.Printf("info level. user:%v\n", user)} func Error(user * user) {// Send SMS messagesdo Something...
	log.Printf("error level. user:%v\n", user)
}


Copy the code