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
?
Answers:
通过这种方式,反向实现了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's 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
吗?添加另一种方法?任何此类更改都需要跨数千个要使用标准反向功能的软件包的许多行代码。
reverse
具有类型的成员Interface
。然后,该成员的方法可以在外部结构上调用或重写。
extend
扩展非抽象子类?对我来说,这是一种方便的方法,可以在使用由internal实现的现有方法时仅覆盖某些方法Interface
。
return r.Interface.Less(j, i)
在调用父实现吗?
好的,可以接受的答案帮助我理解了,但是我决定发表一个我认为更适合我的思维方式的解释。
所述“有效Go”的具有示例的具有嵌入其它接口接口:
// 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's 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
。您可以在规范的struct部分中阅读有关嵌入的信息。
我也会给出解释。所述sort
包定义的未导出类型reverse
,这是一个结构,嵌入Interface
。
type reverse struct {
// This embedded Interface permits Reverse to use the methods of
// another Interface implementation.
Interface
}
这允许反向使用其他接口实现的方法。这就是所谓的composition
,这是Go的强大功能。
该Less
方法用于reverse
调用Less
嵌入Interface
值的方法,但索引会翻转,从而反转排序结果的顺序。
// 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)
}
Len
和Swap
的其他两种方法reverse
由原始Interface
值隐式提供,因为它是一个嵌入式字段。导出的Reverse
函数返回一个reverse
包含原始Interface
值的类型的实例。
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
Less
方法reverse
调用Less
嵌入Interface
值的方法,但是索引被翻转,从而反转了排序结果的顺序。” -这看起来像调用父实现。
在测试中编写模拟时,我发现此功能非常有用。
这是一个例子:
package main_test
import (
"fmt"
"testing"
)
// Item represents the entity retrieved from the store
// It's not relevant in this example
type Item struct {
First, Last string
}
// Store abstracts the DB store
type Store interface {
Create(string, string) (*Item, error)
GetByID(string) (*Item, error)
Update(*Item) error
HealthCheck() error
Close() error
}
// this is a mock implementing Store interface
type storeMock struct {
Store
// healthy is false by default
healthy bool
}
// HealthCheck is mocked function
func (s *storeMock) HealthCheck() error {
if !s.healthy {
return fmt.Errorf("mock error")
}
return nil
}
// IsHealthy is the tested function
func IsHealthy(s Store) bool {
return s.HealthCheck() == nil
}
func TestIsHealthy(t *testing.T) {
mock := &storeMock{}
if IsHealthy(mock) {
t.Errorf("IsHealthy should return false")
}
mock = &storeMock{healthy: true}
if !IsHealthy(mock) {
t.Errorf("IsHealthy should return true")
}
}
通过使用:
type storeMock struct {
Store
...
}
一个不需要模拟所有Store
方法。只有HealthCheck
能够被嘲笑,因为只有这种方法是在使用TestIsHealthy
测试。
test
命令结果下方:
$ go test -run '^TestIsHealthy$' ./main_test.go
ok command-line-arguments 0.003s
一个真实的例子这种使用情况下,一个可以测试时发现AWS SDK。
更明显的是,这是一个丑陋的选择-满足Store
接口所需的最低实现:
type storeMock struct {
healthy bool
}
func (s *storeMock) Create(a, b string) (i *Item, err error) {
return
}
func (s *storeMock) GetByID(a string) (i *Item, err error) {
return
}
func (s *storeMock) Update(i *Item) (err error) {
return
}
// HealthCheck is mocked function
func (s *storeMock) HealthCheck() error {
if !s.healthy {
return fmt.Errorf("mock error")
}
return nil
}
func (s *storeMock) Close() (err error) {
return
}