As a struct field, interface talks about anonymous interfaces in golang structure

Keywords: Go less

In golang, the function of inheritance and override is realized by combination. Perhaps most of us usually use the writing of anonymous struct in struct. Have you ever seen the writing of anonymous interface in struct?

Interface is an interface that is directly an anonymous segment in struct and is written in the standard library sort package as follows:

type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

type reverse struct {
    Interface
}

Let's look at a complete example. The following code is extracted from the sort package:

package main

import (
    "fmt"
)

type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

// Array Implements Interface Interface Interface
type Array []int

func (arr Array) Len() int {
    return len(arr)
}

func (arr Array) Less(i, j int) bool {
    return arr[i] < arr[j]
}

func (arr Array) Swap(i, j int) {
    arr[i], arr[j] = arr[j], arr[i]
}

// Anonymous interface
type reverse struct {
    Interface
}

// Override
func (r reverse) Less(i, j int) bool {
    return r.Interface.Less(j, i)
}

// Constructing reverse Interface
func Reverse(data Interface) Interface {
    return &reverse{data}
}

func main() {
    arr := Array{1, 2, 3}
    rarr := Reverse(arr)
    fmt.Println(arr.Less(0,1))
    fmt.Println(rarr.Less(0,1))
}

The purpose of this in the sort package is to rewrite the interfaces methods and make effective use of the original ones; a reverse Interface can be constructed from the Interface through Reverse. The go language takes advantage of the combination feature and rewrites only a few lines of code.

Comparing with the traditional rewriting method of combining anonymous structures, it may help us better understand the advantages of anonymous interfaces.

package main

import (
    "fmt"
)

type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

type Array []int

func (arr Array) Len() int {
    return len(arr)
}

func (arr Array) Less(i, j int) bool {
    return arr[i] < arr[j]
}

func (arr Array) Swap(i, j int) {
    arr[i], arr[j] = arr[j], arr[i]
}

// Anonymous struct
type reverse struct {
    Array
}

// Rewrite
func (r reverse) Less(i, j int) bool {
    return r.Array.Less(j, i)
}

// Constructing reverse Interface
func Reverse(data Array) Interface {
    return &reverse{data}
}

func main() {
    arr := Array{1, 2, 3}
    rarr := Reverse(arr)
    fmt.Println(arr.Less(0, 1))
    fmt.Println(rarr.Less(0, 1))
}

The above example uses the writing of anonymous structure, which implements the same rewriting function as the previous writing of anonymous interface, or even very similar. But if you compare it carefully, you will find the advantage of anonymous interface. The way of anonymous interface does not depend on the specific implementation, it can rewrite any type of interface that implements it. This is very useful when writing public libraries. If you often look at the source code of some libraries, anonymous interfaces should be written with great familiarity.

Another function of anonymous interfaces is to add some constraints to the structure, which must be constructed using the type of interface that implements it. The structure can contain some other fields, while the interface has only methods and no fields.

package main

import (
    "fmt"
    "reflect"
    "sort"
)

type Array1 []int

func (arr Array1) Len() int {
    return len(arr)
}

func (arr Array1) Less(i, j int) bool {
    return arr[i] < arr[j]
}

func (arr Array1) Swap(i, j int) {
    arr[i], arr[j] = arr[j], arr[i]
}

type Array2 []int

func (arr Array2) Len() int {
    return len(arr)
}

func (arr Array2) Less(i, j int) bool {
    return arr[i] < arr[j]
}

func (arr Array2) Swap(i, j int) {
    arr[i], arr[j] = arr[j], arr[i]
}

type Sortable struct {
    sort.Interface
    // other field
    Type string
}

func NewSortable(i sort.Interface) Sortable {
    t := reflect.TypeOf(i).String()

    return Sortable{
        Interface: i,
        Type:      t,
    }
}

func DoSomething(s Sortable) {
    fmt.Println(s.Type)
    fmt.Println(s.Len())
    fmt.Println(s.Less(0, 1))
}

func main() {
    arr1 := Array1{1, 2, 3}
    arr2 := Array2{3, 2, 1, 0}

    DoSomething(NewSortable(arr1))
    DoSomething(NewSortable(arr2))
}

Posted by Garth Farley on Wed, 15 May 2019 17:03:04 -0700