SoFunction
Updated on 2025-03-05

Summary of the use of Golang interface function

What is an interface function? As the name suggests, interface functions refer to the implementation of interfaces using functions, which will be very simple when calling. This method is suitable for interfaces with only one function.

Here we take iterating a map as an example to demonstrate the techniques of this implementation.

General interface implementation

The defer statement is used to delay function calls. Each time a function is pushed into the stack, and the delayed function is taken out and executed before the function returns. The delay function can have parameters:

  • The parameters of the delay function are determined when the defer statement appears (the current value is passed);
  • Delay function execution is executed in the order of back-in-first-out;
  • The delay function can operate on the named return value of the main function (modify the return value);
type Handler interface {
    DoFunc(k, v interface{})
}
func DoEach(m map[interface{}]interface{}, h Handler) {
    if m != nil && len(m) > 0 {
        for k, v := range m {
            (k, v)
        }
    }
}

Here we define a Handler interface, which has only one DoFunc method, which receives two parameters, k and v. This is an interface, and we will implement it later, and what we do is determined by our implementation.

Then we define a DoEach function, which is the function of which is iteratively passed map parameters, and then pass each key and value of map to the Handler's DoFunc method.

Specifically determined by the implementation of this Handler, which is also interface-oriented programming.

If you want to say more, it is better to have some practical examples: use the DoEach method and Handler interface we just defined.

package main
import "fmt"
type Handler interface {
    DoFunc(k, v interface{})
}
func DoEach(m map[interface{}]interface{}, h Handler) {
    if m != nil && len(m) > 0 {
        for k, v := range m {
            (k, v)
        }
    }
}
type greet string
func ( g greet) DoFunc(k, v interface{}) {
    ("%s, under %s, my killing skill is %s\n", g, k, v)
}
func main() {
    persons := make(map[interface{}]interface{})
    persons["Qiao Feng"] = "Dragon Claw Hand"
    persons["Jiumozhi"] = "Little *nggong"
    persons["Murong Fu"] = "The stars change"
    var g greet = "Heroes"
    DoEach(persons, g)
}

Output:

Dear heroes, in Xia Qiao Feng, my ultimate skill is Dragon Claw Hand
Dear heroes, in the lower Jiumozhi, my ultimate skill is Xiao Wuxianggong
Dear heroes, in the lower Murong Fu, my ultimate skill is to move the stars

In the above implementation, we define a map to store several big shots. The map key is the big shot's name and the value is the big shot's unique skill. greet is our newly defined type.

It corresponds to the basic type string. The greet implements the Handler interface and prints the self-introduction information.

Interface function appearance

Regarding the above implementation, we can find that there are two things that are not very good:

  • Because the Handler interface must be implemented, the DoFunc method name cannot be modified and a more meaningful name cannot be defined.
  • A new type must be defined in order to implement the Handler interface and use the DoEach function

First, we solve the first problem first, and define a more meaningful method name based on what we do, such as self-introduction in the example.

So is it better for us to use selfintroduction than the semantic method of DoFunc?

If the caller changes the method name, then the Handler interface cannot be implemented. What should I do if I still use the DoEach method? That is, the implementation of Handler provided by the person who provides the DoEach function.

Let's modify the code as follows:

type HandlerFunc func(k, v interface{})
 
func (f HandlerFunc) DoFunc(k, v interface{}) {
    f(k, v)
}

The above code we define a new type HandlerFunc, which is a func(k, v interface{}) type, and then this new HandlerFunc implements the Handler interface (in the original implementation method

type Handler interface { DoFunc(k, v interface{}) }

), the implementation of the DoFunc method is to call HandlerFunc itself, because a variable of type HandlerFunc is a method. Now we use this method to achieve the same effect.

The complete code is as follows:

package main
import "fmt"
type Handler interface {
    DoFunc(k, v interface{})
}
type HandlerFunc func(k, v interface{})
func (f HandlerFunc) DoFunc(k, v interface{}) {
    f(k, v)
}
type greet string
func (g greet) selfintroduction(k, v interface{}) {
    ("%s, under %s, my killing skill is %s\n", g, k, v)
}
func DoEach(m map[interface{}]interface{}, h Handler) {
    if m != nil && len(m) > 0 {
        for k, v := range m {
            (k, v)
        }
    }
}
func main() {
    persons := make(map[interface{}]interface{})
    persons["Qiao Feng"] = "Dragon Claw Hand"
    persons["Jiumozhi"] = "Little *nggong"
    persons["Murong Fu"] = "The stars change"
    var g greet = "Heroes"
    DoEach(persons, HandlerFunc())
} 

Output:

Dear heroes, in Xia Qiao Feng, my ultimate skill is Dragon Claw Hand
Dear heroes, in the lower Jiumozhi, my ultimate skill is Xiao Wuxianggong
Dear heroes, in the lower Murong Fu, my ultimate skill is to move the stars

It's still about the same original implementation, just change the original interface method name DoFunc to selfetroduction. HandlerFunc() is not a method call, but a transformation, because selfintroduction and HandlerFunc are of the same type.

So it can be forced to transform. After the transformation, because HandlerFunc implements the Handler interface, we can continue to use the original DoEach method.

Further transformation

Now the naming problem is solved, but is it not good to force each time? We continue to refactor it, and we can use a new method of defining a function to help the caller force transformation.

The complete code is as follows:

package main
import "fmt"
type Handler interface {
    DoFunc(k, v interface{})
}
type HandlerFunc func(k, v interface{})
func (f HandlerFunc) DoFunc(k, v interface{}) {
    f(k, v)
}
type greet string
func (g greet) selfintroduction(k, v interface{}) {
    ("%s, under %s, my killing skill is %s\n", g, k, v)
}
func DoEach(m map[interface{}]interface{}, h Handler) {
    if m != nil && len(m) > 0 {
        for k, v := range m {
            (k, v)
        }
    }
}
func EachFunc(m map[interface{}]interface{}, f func(k, v interface{})) {
    DoEach(m, HandlerFunc(f))
}
func main() {
    persons := make(map[interface{}]interface{})
    persons["Qiao Feng"] = "Dragon Claw Hand"
    persons["Jiumozhi"] = "Little *nggong"
    persons["Murong Fu"] = "The stars change"
    var g greet = "Heroes"
    EachFunc(persons, )
} 

Above we have added a EachFunc function to help the caller force transformation, so the caller doesn't have to do it by himself.

Now we find that the EachFunc function receives a function of type func(k, v interface{}) and there is no need to implement the original Handler interface, so we can remove the new type and do not use it.

After removing the custom type greet, the whole code is more concise. Is it better to read? The complete code of the clean and clean code is as follows:

package main
import "fmt"
type Handler interface {
    DoFunc(k, v interface{})
}
type HandlerFunc func(k, v interface{})
func (f HandlerFunc) DoFunc(k, v interface{}) {
    f(k, v)
}
func DoEach(m map[interface{}]interface{}, h Handler) {
    if m != nil && len(m) > 0 {
        for k, v := range m {
            (k, v)
        }
    }
}
func EachFunc(m map[interface{}]interface{}, f func(k, v interface{})) {
    DoEach(m, HandlerFunc(f))
}
func selfintroduction(k, v interface{}) {
    ("Heroes, in the next %s, my ultimate skill is %s\n", k, v)
}
func main() {
    persons := make(map[interface{}]interface{})
    persons["Qiao Feng"] = "Dragon Claw Hand"
    persons["Jiumozhi"] = "Little *nggong"
    persons["Murong Fu"] = "The stars change"
    EachFunc(persons, selfintroduction)
}

The above is finished writing about the functional interface. If you pay attention carefully, you will find that it is very similar to the methods we usually use. In fact, this is how the interface is implemented.

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}
 
func Handle(pattern string, handler Handler) {
    (pattern, handler)
}
 
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    (pattern, handler)
}

This is a very good technique, providing two functions, which can be used in interface mode or in method mode.

Corresponding to the two functions DoEach and EachFunc in our example, they are flexible and convenient, and more in line with natural language rules.

No matter what industry you are in, just do two things well, one is your profession and the other is your character. Professionalism determines your existence, character determines your connections, and the rest is persistence and win more trust with kindness, professionalism and sincerity.

This is the end of this article about the skills of using Golang interface-type functions. For more related content on using Golang interfaces, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!