sort
パッケージ:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
...
type reverse struct {
Interface
}
Interface
構造体の匿名インターフェースの意味は何reverse
ですか?
sort
パッケージ:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
...
type reverse struct {
Interface
}
Interface
構造体の匿名インターフェースの意味は何reverse
ですか?
回答:
このようにして、リバースはを実装しsort.Interface
、他のすべてを定義することなく特定のメソッドをオーバーライドできます
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
// 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)
、親実装を呼び出していますか?
sort.Sort(sort.Reverse(sort.IntSlice(example)))
。私にとってここでの問題点は、Sortメソッドが逆構造体にプロモートされますが、呼び出しは非メンバー(レシーバー)スタイルです。
承諾した回答で理解できましたが、自分の考え方に合った説明を投稿することにしました。
「有効ゴー」が埋め込まれた他のインターフェースを有するインターフェースの例を有します。
// 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
たときに実際に発生することです。埋め込みについては、仕様の構造体セクションで読むことができます。
sort.Sort(sort.Reverse(sort.IntSlice(example)))
。私にとってここでの問題点は、Sortメソッドが逆構造体にプロモートされますが、呼び出しは非メンバー(レシーバー)スタイルです。
Sort
メソッドはプロモートされません。満足するものが必要でsort.Interface
あり、リバースはそのようなものです。埋め込まれたsort.Interface
データの関連するメソッドを変更するだけで、結果のソートがリバースされます。
私も説明します。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's Less method.
func (r reverse) Less(i, j int) bool {
return r.Interface.Less(j, i)
}
Len
そして、Swap
の他の2つの方法は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
現実の世界の例テストするときに1を見つけることができます。このユースケースの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
}