sort
пакет:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
...
type reverse struct {
Interface
}
В чем смысл анонимного интерфейса Interface
в struct reverse
?
sort
пакет:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
...
type reverse struct {
Interface
}
В чем смысл анонимного интерфейса Interface
в struct reverse
?
Таким образом, обратное реализует 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
?Любое из этих изменений потребует гораздо большего количества строк кода для тысяч пакетов, которые хотят использовать стандартную обратную функциональность.
Хорошо, принятый ответ помог мне понять, но я решил опубликовать объяснение, которое, я думаю, лучше подходит для моего мышления.
"Эффективный переход" содержит пример интерфейсов, имеющих встроенные другие интерфейсы:
// 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"})
}
Утверждение
type reverse struct {
Interface
}
позволяет инициализировать reverse
всем, что реализует интерфейс Interface
. Пример:
&reverse{sort.Intslice([]int{1,2,3})}
Таким образом, все методы, реализованные встроенным значением Interface
, становятся заполненными снаружи, в то время как вы по-прежнему можете переопределить некоторые из них в reverse
, например Less
, чтобы отменить сортировку.
Это то, что на самом деле происходит, когда вы используете sort.Reverse
. Вы можете прочитать о вложении в разделе структуры спецификации.
Я также дам свое объяснение. Пакет 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}
}