sort
paket:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
...
type reverse struct {
Interface
}
Anonim arayüzünün anlamı nedir Interface
yapı içinde reverse
?
sort
paket:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
...
type reverse struct {
Interface
}
Anonim arayüzünün anlamı nedir Interface
yapı içinde reverse
?
Yanıtlar:
Bu şekilde, tersi uygular sort.Interface
ve diğerlerini tanımlamak zorunda kalmadan belirli bir yöntemi geçersiz kılabiliriz.
type reverse struct {
// This embedded Interface permits Reverse to use the methods of
// another Interface implementation.
Interface
}
O swapları nasıl burada Bildirimi (j,i)
yerine (i,j)
yapı için ilan sadece yöntem ve ayrıca bu reverse
bile reverse
uygulamaksort.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)
}
Bu yöntemin içinde hangi yapı geçirilirse aktarılsın, onu yeni bir reverse
yapıya dönüştürüyoruz .
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
Bu yaklaşım mümkün olmasaydı ne yapmanız gerektiğini düşünürseniz gerçek değer gelir.
Reverse
yöntemini sort.Interface
?Bu değişikliklerin herhangi biri, standart ters işlevselliği kullanmak isteyen binlerce paket içinde çok daha fazla kod satırı gerektirecektir.
reverse
, tipte bir üyeye sahip olmasıdır Interface
. Bu üye daha sonra dış yapı üzerinde çağrılabilir veya geçersiz kılınabilir yöntemlerine sahiptir.
extend
soyut olmayan alt sınıfları genişletmek için? Bana göre bu, dahili olarak uygulanan mevcut yöntemleri kullanırken yalnızca belirli yöntemleri geçersiz kılmanın kullanışlı bir yolu olabilir Interface
.
return r.Interface.Less(j, i)
üst uygulamayı çağırmak mı?
sort.Sort(sort.Reverse(sort.IntSlice(example)))
. Benim için buradaki acı nokta: Sıralama yöntemi ters yapıya yükseltilir, ancak çağrı üye olmayan (alıcı) stildir.
Tamam, kabul edilen cevap anlamama yardımcı oldu, ancak düşünme tarzıma daha uygun olduğunu düşündüğüm bir açıklama göndermeye karar verdim.
"Etkili git" gömülü diğer arayüzleri olan arayüzleri örnek vardır:
// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
Reader
Writer
}
ve diğer yapıları gömülü bir yapı:
// ReadWriter stores pointers to a Reader and a Writer.
// It implements io.ReadWriter.
type ReadWriter struct {
*Reader // *bufio.Reader
*Writer // *bufio.Writer
}
Ancak bir arayüzün gömülü olduğu bir yapıdan söz edilmiyor. Bunu sort
pakette görünce kafam karıştı :
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
...
type reverse struct {
Interface
}
Ancak fikir basit. Neredeyse aynı:
type reverse struct {
IntSlice // IntSlice struct attaches the methods of Interface to []int, sorting in increasing order
}
IntSlice
terfi etme yöntemleri reverse
.
Ve bu:
type reverse struct {
Interface
}
araçları sort.reverse
uygular arayüzü herhangi struct'ı gömebilirsiniz sort.Interface
ve arayüz sahip olduğunu ne olursa olsun yöntemleri, onlar terfi edilecek reverse
.
sort.Interface
Less(i, j int) bool
artık geçersiz kılınabilen bir yönteme sahiptir:
// 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)
}
Anlamaktaki kafa karışıklığım
type reverse struct {
Interface
}
bir yapının her zaman sabit bir yapıya, yani sabit tipte sabit sayıda alana sahip olduğunu düşünmüştüm.
Ama şu yanlış olduğumu kanıtlıyor:
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"})
}
İfade
type reverse struct {
Interface
}
reverse
arabirimi uygulayan her şeyi başlatmanızı sağlar Interface
. Misal:
&reverse{sort.Intslice([]int{1,2,3})}
Bu şekilde, gömülü Interface
değer tarafından uygulanan tüm yöntemler reverse
, örneğin Less
sıralamayı tersine çevirmek için bunlardan bazılarını geçersiz kılmaya devam ederken, dışarıya yerleştirilir .
Bu, kullandığınızda gerçekte olan şeydir sort.Reverse
. Spesifikasyonun struct bölümüne yerleştirme hakkında bilgi edinebilirsiniz .
sort.Sort(sort.Reverse(sort.IntSlice(example)))
. Benim için buradaki acı nokta: Sıralama yöntemi ters yapıya yükseltilir, ancak çağrı üye olmayan (alıcı) stildir.
Sort
yöntem yükseltilmez, tatmin edici sort.Interface
bir şey alır ve tersine çevirir öyle bir şey, sadece gömülü sort.Interface
verilerinin ilgili yöntemlerini değiştirir, böylece ortaya çıkan sıralama tersine çevrilir.
Ben de açıklamamı vereceğim. sort
Paket, unexported tür tanımlar reverse
bir yapı, bu gömme olup, Interface
.
type reverse struct {
// This embedded Interface permits Reverse to use the methods of
// another Interface implementation.
Interface
}
Bu, Reverse'nin başka bir Arayüz uygulamasının yöntemlerini kullanmasına izin verir. Bu sözde composition
, Go'nun güçlü bir özelliğidir.
Less
Yöntemi reverse
çağrıları Less
gömülü bir yöntem Interface
değeri ancak indisleri ile sıralama sonuçları sırası ters, ters çevrilmiş.
// 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
ve Swap
diğer iki yöntem, gömülü bir alan olduğu reverse
için orijinal Interface
değer tarafından örtük olarak sağlanır . Dışa aktarılan Reverse
işlev reverse
, orijinal Interface
değeri içeren türün bir örneğini döndürür .
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
Less
Yöntemi gömülü değerin yöntemini reverse
çağırır , ancak endeksler ters çevrilerek sıralama sonuçlarının sırasını tersine çevirir." - bu, üst uygulamanın çağrılmasına benziyor. Less
Interface
Yazarken ben çok yararlı bu özelliği bulmak mocks içinde testler .
İşte böyle bir örnek:
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")
}
}
Kullanarak:
type storeMock struct {
Store
...
}
Tüm Store
yöntemlerle dalga geçmeye gerek yok . Sadece HealthCheck
tek bu yöntem kullanıldığı için, alay edilebilir TestIsHealthy
testi.
test
Komutun sonucunun altında :
$ go test -run '^TestIsHealthy$' ./main_test.go
ok command-line-arguments 0.003s
Bir gerçek dünya örneği test ederken bu kullanım örneği birinin bulabilirsiniz AWS SDK .
Daha da açık hale getirmek için, işte çirkin alternatif - Store
arayüzü tatmin etmek için uygulanması gereken minimum alternatif :
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
}