Значение структуры со встроенным анонимным интерфейсом?

sort пакет:

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

...

type reverse struct {
    Interface
}

В чем смысл анонимного интерфейса Interface в struct reverse?

Ответ 1

Таким образом, обратное реализует sort.Interface, и мы можем переопределить определенный метод без необходимости определять все остальные

type reverse struct {
        // This embedded Interface permits Reverse to use the methods of
        // another Interface implementation.
        Interface
}

Обратите внимание, как здесь он меняет (j,i) вместо (i,j), а также это единственный метод, объявленный для struct reverse, даже если reverse реализовать sort.Interface

// Less returns the opposite of the embedded implementation Less method.
func (r reverse) Less(i, j int) bool {
        return r.Interface.Less(j, i)
}

Любая структура, передаваемая внутри этого метода, преобразует ее в новую структуру reverse.

// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
        return &reverse{data}
}

Реальная ценность возникает, если вы думаете, что вам нужно сделать, если этот подход невозможен.

  • Добавьте еще один метод reverse в sort.Interface?
  • Создать другой ReverseInterface?
  • ...?

Любое из этих изменений потребует гораздо большего количества строк кода для тысяч пакетов, которые хотят использовать стандартную обратную функциональность.

Ответ 2

Хорошо, принятый ответ помог мне понять, но я решил опубликовать объяснение, которое, я думаю, лучше подходит для моего мышления.

"Эффективный переход" содержит пример интерфейсов, имеющих встроенные другие интерфейсы:

// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
    Reader
    Writer
}

и структуры с встроенными другими структурами:

// ReadWriter stores pointers to a Reader and a Writer.
// It implements io.ReadWriter.
type ReadWriter struct {
    *Reader  // *bufio.Reader
    *Writer  // *bufio.Writer
}

Но нет упоминания о структуре с встроенным интерфейсом. Я был в замешательстве, увидев это в пакете sort:

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

...

type reverse struct {
    Interface
}

Но идея проста. Это почти то же самое, что:

type reverse struct {
    IntSlice  // IntSlice struct attaches the methods of Interface to []int, sorting in increasing order
}

методы IntSlice продвигаются до reverse.

И это:

type reverse struct {
    Interface
}

означает, что sort.reverse может встраивать любую структуру, реализующую интерфейс sort.Interface, и любые методы, которые имеют интерфейс, они будут продвигаться до reverse.

sort.Interface имеет метод Less(i, j int) bool, который теперь можно переопределить:

// Less returns the opposite of the embedded implementation Less method.
func (r reverse) Less(i, j int) bool {
    return r.Interface.Less(j, i)
}

Мое замешательство в понимании

type reverse struct {
    Interface
}

заключалось в том, что я думал, что структура всегда имеет фиксированную структуру, т.е. фиксированное число полей фиксированных типов.

Но следующее доказывает, что я ошибаюсь:

package main

import "fmt"

// some interface
type Stringer interface {
    String() string
}

// a struct that implements Stringer interface
type Struct1 struct {
    field1 string
}

func (s Struct1) String() string {
    return s.field1
}


// another struct that implements Stringer interface, but has a different set of fields
type Struct2 struct {
    field1 []string
    dummy bool
}

func (s Struct2) String() string {
    return fmt.Sprintf("%v, %v", s.field1, s.dummy)
}


// container that can embedd any struct which implements Stringer interface
type StringerContainer struct {
    Stringer
}


func main() {
    // the following prints: This is Struct1
    fmt.Println(StringerContainer{Struct1{"This is Struct1"}})
    // the following prints: [This is Struct1], true
    fmt.Println(StringerContainer{Struct2{[]string{"This", "is", "Struct1"}, true}})
    // the following does not compile:
    // cannot use "This is a type that does not implement Stringer" (type string)
    // as type Stringer in field value:
    // string does not implement Stringer (missing String method)
    fmt.Println(StringerContainer{"This is a type that does not implement Stringer"})
}

Ответ 3

Утверждение

type reverse struct {
    Interface
}

позволяет инициализировать reverse всем, что реализует интерфейс Interface. Пример:

&reverse{sort.Intslice([]int{1,2,3})}

Таким образом, все методы, реализованные встроенным значением Interface, становятся заполненными снаружи, в то время как вы по-прежнему можете переопределить некоторые из них в reverse, например Less, чтобы отменить сортировку.

Это то, что на самом деле происходит, когда вы используете sort.Reverse. Вы можете прочитать о вложении в разделе структуры спецификации.

Ответ 4

Я также дам свое объяснение. Пакет sort определяет неэкспортированный тип reverse, который представляет собой структуру, которая включает Interface.

type reverse struct {
    // This embedded Interface permits Reverse to use the methods of
    // another Interface implementation.
    Interface
}

Это позволяет Reverse использовать методы другой реализации интерфейса. Это так называемый composition, который является мощной функцией Go.

Метод Less для reverse вызывает метод Less встроенного значения Interface, но с индексированием перевернуты, изменяя порядок результатов сортировки.

// Less returns the opposite of the embedded implementation Less method.
func (r reverse) Less(i, j int) bool {
    return r.Interface.Less(j, i)
}

Len и Swap другие два метода reverse, неявно предоставляются исходным значением Interface, потому что это встроенное поле. Экспортированная функция reverse возвращает экземпляр типа reverse, который содержит исходное значение Interface.

// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
    return &reverse{data}
}