关于go:带有嵌入式匿名接口的结构的含义?


Meaning of a struct with embedded anonymous interface?

sort软件包:

1
2
3
4
5
6
7
8
9
10
11
type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

...

type reverse struct {
    Interface
}

struct reverse中的匿名接口Interface是什么意思?


这样,反向实现了sort.Interface,我们可以覆盖特定的方法
无需定义其他所有对象

1
2
3
4
5
type reverse struct {
        // This embedded Interface permits Reverse to use the methods of
        // another Interface implementation.
        Interface
}

请注意,这里是如何交换(j,i)而不是(i,j)的,这也是为结构reverse声明的唯一方法,即使reverse实现sort.Interface

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

无论此方法内部传递了什么结构,我们都会将其转换为新的reverse结构。

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

真正的价值在于,如果您认为如果无法采用这种方法,该怎么办。

  • sort.Interface中添加另一个reverse方法?
  • 创建另一个ReverseInterface?
  • ...?
  • 任何此类更改都将需要跨数千个要使用标准反向功能的软件包的许多行代码。


    好的,可以接受的答案帮助我理解了,但是我决定发表一个我认为更适合我的思维方式的解释。

    " Effective Go"具有嵌入了其他接口的接口示例:

    1
    2
    3
    4
    5
    // ReadWriter is the interface that combines the Reader and Writer interfaces.
    type ReadWriter interface {
        Reader
        Writer
    }

    以及一个嵌入了其他结构的结构:

    1
    2
    3
    4
    5
    6
    // ReadWriter stores pointers to a Reader and a Writer.
    // It implements io.ReadWriter.
    type ReadWriter struct {
        *Reader  // *bufio.Reader
        *Writer  // *bufio.Writer
    }

    但是没有提及嵌入接口的结构。我在sort包中看到这个感到困惑:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    type Interface interface {
        Len() int
        Less(i, j int) bool
        Swap(i, j int)
    }

    ...

    type reverse struct {
        Interface
    }

    但是这个想法很简单。几乎与以下内容相同:

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

    IntSlice的方法被提升为reverse

    和这个:

    1
    2
    3
    type reverse struct {
        Interface
    }

    表示sort.Reverse可以嵌入实现接口sort.Interface的任何结构,以及该接口具有的任何方法,它们都将被提升为reverse

    sort.Interface具有方法Less(i, j int) bool,该方法现在可以被覆盖:

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

    我对理解的困惑

    1
    2
    3
    type reverse struct {
        Interface
    }

    是因为我认为结构始终具有固定的结构,即固定类型的字段的数量固定。

    但是以下事实证明我错了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    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"})
    }


    该声明

    1
    2
    3
    type reverse struct {
        Interface
    }

    使您可以使用实现接口Interface的所有内容初始化reverse。例:

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

    这样,由嵌入式Interface值实现的所有方法都将填充到外部,而您仍然能够在reverse中覆盖其中的某些方法,例如Less以颠倒排序。

    这是使用sort.Reverse时实际发生的情况。您可以在规范的struct部分中阅读有关嵌入的信息。


    我也会给出解释。 sort包定义了嵌入Interface的未导出类型reverse,它是一种结构。

    1
    2
    3
    4
    5
    type reverse struct {
        // This embedded Interface permits Reverse to use the methods of
        // another Interface implementation.
        Interface
    }

    这允许反向使用其他接口实现的方法。这就是所谓的composition,它是Go的强大功能。

    reverseLess方法调用嵌入的Interface值的Less方法,但是索引被翻转,从而反转了排序结果的顺序。

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

    LenSwap其他两个reverse方法由原始Interface值隐式提供,因为它是一个嵌入式字段。导出的reverse函数返回包含原始Interface值的reverse类型的实例。

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