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)
}
สิ่งที่ struct จะถูกส่งภายในวิธีนี้เราแปลงเป็นใหม่reverse
struct
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
มูลค่าที่แท้จริงเกิดขึ้นหากคุณคิดว่าคุณจะต้องทำอย่างไรหากแนวทางนี้ไม่สามารถทำได้
Reverse
วิธีการอื่นในsort.Interface
?การเปลี่ยนแปลงใด ๆ นี้จะต้องใช้โค้ดอีกหลายบรรทัดในหลายพันแพ็กเกจที่ต้องการใช้ฟังก์ชันย้อนกลับมาตรฐาน
reverse
มีสมาชิกInterface
จากประเภท จากนั้นสมาชิกนี้มีเมธอดที่เรียกได้บนโครงสร้างด้านนอกหรือแทนที่ได้
extend
สำหรับการขยายคลาสย่อยที่ไม่ใช่นามธรรม? Interface
ให้ฉันนี้อาจเป็นวิธีที่มีประโยชน์ในการแทนที่วิธีการบางอย่างเท่านั้นในขณะที่ใช้คนที่มีอยู่ว่าจะดำเนินการโดยภายใน
return r.Interface.Less(j, i)
กำลังเรียกใช้พาเรนต์หรือไม่
sort.Sort(sort.Reverse(sort.IntSlice(example)))
(ซึ่งเป็นสิ่งจำเป็นเพื่อจัดเรียงจริงอะไร): สำหรับฉันแล้วจุดเจ็บปวดที่นี่: วิธีการเรียงลำดับได้รับการเลื่อนระดับเป็นโครงสร้างย้อนกลับ แต่การโทรไม่ใช่สไตล์สมาชิก (ผู้รับ)
โอเคคำตอบที่ยอมรับช่วยให้ฉันเข้าใจ แต่ฉันตัดสินใจโพสต์คำอธิบายที่ฉันคิดว่าเหมาะกับวิธีคิดของฉันมากกว่า
"มีผลบังคับใช้ไป"มีตัวอย่างของอินเตอร์เฟซที่มีการฝังตัวเชื่อมต่ออื่น ๆ :
// 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
สามารถฝัง struct ใด ๆ ที่ดำเนินการติดต่อและสิ่งที่วิธีการที่อินเตอร์เฟซที่มีพวกเขาจะได้รับการเลื่อนตำแหน่งให้เป็น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.Interface
และย้อนกลับเป็นสิ่งนั้นเพียงแค่เปลี่ยนวิธีการที่เกี่ยวข้องของsort.Interface
ข้อมูลที่ฝังไว้เพื่อให้การเรียงลำดับผลลัพธ์กลับ
ฉันจะให้คำอธิบายของฉันด้วย sort
แพคเกจที่กำหนดประเภท unexported reverse
ซึ่งเป็น struct, 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
อีกสองวิธีการreverse
ระบุโดยปริยายโดยInterface
ค่าดั้งเดิมเนื่องจากเป็นฟิลด์ฝังตัว Reverse
ฟังก์ชันที่ส่งออกจะส่งคืนอินสแตนซ์ของreverse
ชนิดที่มีInterface
ค่าดั้งเดิม
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
Less
วิธีการreverse
เรียกLess
เมธอดของInterface
ค่าฝังตัวแต่เมื่อดัชนีพลิกกลับลำดับของผลลัพธ์การจัดเรียง" - ดูเหมือนการเรียกใช้งานหลัก
ผมพบว่าคุณลักษณะนี้มีประโยชน์มากเมื่อเขียนmocksในการทดสอบ
นี่คือตัวอย่าง:
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
}