Jun 01, 2021 Article blog
This article is intended to introduce some other methods of
interface
The basics of
interface
can be seen in another article:
Go Language Polymorphism and Interface Use
Interfaces are a writing specification in
Java
and other languages, and in
golang
interface
is actually a value that can be passed like a value.
And at the bottom of it, it's actually a tuple of values and types.
Here's an example from
golang
official documentation:
package main
import (
"fmt"
"math"
)
type I interface {
M()
}
type T struct {
S string
}
func (t *T) M() {
fmt.Println(t.S)
}
type F float64
func (f F) M() {
fmt.Println(f)
}
func main() {
var i I
i = &T{"Hello"}
describe(i)
i.M()
i = F(math.Pi)
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
In the code above, a method called describe is defined, in which we output two values, one for interface i and the other for interface i.
(Recommended course: Go tutorial)
The results we output are as follows:
You can see that the interface stores information about both instances of the corresponding structure and the type of structure.
So
interface
can be understood as a special type.
Indeed, we can understand
interface
as a universal data type that can receive any type of value.
Let's look at the following usage:
var a1 interface{} = 1
var a2 interface{} = "abc"
list := make([]interface{}, 0)
list = append(list, a1)
list = append(list, a2)
fmt.Println(list)
In the code we create a
slice
of the
interface{}
which can receive any type of value and instance. I
n addition, we can also receive the value of any structure
interface{}
the type interface. T
here may be some confusion here, but it's easy to figure it out.
interface
represents a type that can receive the value of any type that implements the method specified in
interface
When we define
inteface{}
we actually define an empty
interface
which is equivalent to an empty
interface
that does not require any method, so any type can receive it, which is why it becomes a universal type.
Of course there is no problem with our reception, the question is how do we use the values of these
interface
types?
One way is that we can judge the type of variable for a
interface
T
he method
interface
judgment is very simple, and we use
.(type)
method of judgment. I
t returns a value and a
bool
type tag, just as the
key
value of the
map
is judged.
We can use this tag to determine if this type is correct.
if v, ok := a1.(int); ok {
fmt.Println(v)
}
Switch
switch
also possible if there are more types:
switch v := i.(type) {
case int:
fmt.Println("int")
case string:
fmt.Println("string")
}
interface
empty value of the interface type is
nil
and
None
in
Python
means that a pointer points to the empty. I
f we call a method on an empty pointer in
Java
or another language, it triggers
NullPointerMethodError
which is the empty pointer error.
This is also the most common error we beginners encounter in programming, often because we forget to initialize the declaration.
But not in
golang
even
nil
can call
interface
method.
For example:
type T struct {
S string
}
func (t *T) M() {
fmt.Println(t.S)
}
func main() {
var i I
var t *T
i = t
i.M()
}
We
t
to
i
and the problem is that
t
is not initialized, so it is a
nil
and then our
i
is also a
nil
W
e call the
M
method for
nil
and in the
M
method we print the local variable S for
t
S
Because
t
is a
nil
at the moment and it does not have this variable, it throws an error of
invalid memory address or nil pointer derefernce
which is an error in addressing an empty pointer.
To fix this error, it's simple, we can judge
t
in the
M
method, and if
t
find that t is a
nil
then we skip the logic of execution.
When we change the
M
function to this, we don't trigger the problem of empty pointers.
func (t *T) M() {
if t == nil {
fmt.Println("nil")
return
}
fmt.Println(t.S)
}
The problem of
nil
triggering exceptions is also one of the problems that beginners often encounter, which also requires us to remember to determine whether the object being called is
nil
when implementing the inner method of the structure, so as to avoid unnecessary problems.
(Recommended course: Go Web programming)
We all know that polymorphism is achieved through
interface
in
golang
and as long as the function defined in
interface
is implemented, then we can assign the corresponding instance to this
interface
type.
This may seem like a problem, but there's still a little bit of a problem with actual execution. Let's say we have this piece of code:
type Integer int
type Operation interface {
Less(b Integer) bool
Add(b Integer)
}
func (a Integer) Less(b Integer) bool {
return a < b
}
func (a *Integer) Add(b Integer) {
*a += b
}
This code is very simple, we define an
Operation
interface
and implement two methods of
Integer
type. O
n the face of it everything is fine, but there is one detail.
Less
less and
Add
methods are different for the type,
Less
method we don't need to modify the original value, so we pass in the value of
Integer
and
Add
method, we need to modify the original value, so the type we pass in is the pointer to
Integer
So the question is, the two methods are of different types, can we assign its value to
Operation
interface
I
f so, should we pass a value or a pointer?
Which of the second and third lines of code is correct?
var a Integer = 1
var b Operation = &a
var b Operation = a
The answer is that the second line is correct for a simple reason, because after we pass in the pointer,
golang
compiler automatically generates a new
Less
method.
Calling the original method in this converted type method is equivalent to making a layer of transit.
func (a *Integer) Less(b Integer) bool{
return (*a).Less(b)
}
So what's the other way around? We also write the code:
func (a Integer) Add (b Integer) {
(&a).Add(b)
}
Obviously this is not possible, because the function can only be modified after execution by the value of
a
parameter in
Add
method, and there is no way to modify the original value.
This doesn't match what we want, so
golang
didn't choose this strategy.
(Recommended micro-class: Go micro-class)
In today's article, we describe some of the advanced uses of
interface
in
golang
such as using it as a universal type to receive values in various formats.
For
interface
the problem of empty pointer calls to interface, and the problem of inconsistent receive types of two functions in
interface
That is to say, in the
go
language,
interface
is both a polymorphic implementation specification and an all-powerful type derived from the function, this design is really amazing. T
he skilled use of
interface
can greatly reduce the complexity of our coding and the efficiency of our operations among some issues. T
his is also one of
golang
native advantages.
I hope the above related introduction can be helpful to everyone.
Source: www.toutiao.com/a6859567247216771587/