ฉันคุ้นเคยกับความจริงที่ว่าใน Go อินเทอร์เฟซกำหนดฟังก์ชันการทำงานแทนที่จะเป็นข้อมูล คุณใส่ชุดวิธีการลงในอินเทอร์เฟซ แต่คุณไม่สามารถระบุฟิลด์ใด ๆ ที่จำเป็นสำหรับสิ่งที่ใช้อินเทอร์เฟซนั้น
ตัวอย่างเช่น:
// Interface
type Giver interface {
Give() int64
}
// One implementation
type FiveGiver struct {}
func (fg *FiveGiver) Give() int64 {
return 5
}
// Another implementation
type VarGiver struct {
number int64
}
func (vg *VarGiver) Give() int64 {
return vg.number
}
ตอนนี้เราสามารถใช้อินเทอร์เฟซและการใช้งานได้:
// A function that uses the interface
func GetSomething(aGiver Giver) {
fmt.Println("The Giver gives: ", aGiver.Give())
}
// Bring it all together
func main() {
fg := &FiveGiver{}
vg := &VarGiver{3}
GetSomething(fg)
GetSomething(vg)
}
/*
Resulting output:
5
3
*/
ตอนนี้สิ่งที่คุณทำไม่ได้มีดังนี้:
type Person interface {
Name string
Age int64
}
type Bob struct implements Person { // Not Go syntax!
...
}
func PrintName(aPerson Person) {
fmt.Println("Person's name is: ", aPerson.Name)
}
func main() {
b := &Bob{"Bob", 23}
PrintName(b)
}
อย่างไรก็ตามหลังจากเล่นกับอินเทอร์เฟซและโครงสร้างแบบฝังฉันได้ค้นพบวิธีที่จะทำสิ่งนี้หลังจากแฟชั่น:
type PersonProvider interface {
GetPerson() *Person
}
type Person struct {
Name string
Age int64
}
func (p *Person) GetPerson() *Person {
return p
}
type Bob struct {
FavoriteNumber int64
Person
}
เนื่องจากโครงสร้างที่ฝังไว้ Bob จึงมีทุกสิ่งที่บุคคลมี นอกจากนี้ยังใช้อินเทอร์เฟซ PersonProvider ดังนั้นเราจึงสามารถส่ง Bob ไปสู่ฟังก์ชันที่ออกแบบมาเพื่อใช้อินเทอร์เฟซนั้นได้
func DoBirthday(pp PersonProvider) {
pers := pp.GetPerson()
pers.Age += 1
}
func SayHi(pp PersonProvider) {
fmt.Printf("Hello, %v!\r", pp.GetPerson().Name)
}
func main() {
b := &Bob{
5,
Person{"Bob", 23},
}
DoBirthday(b)
SayHi(b)
fmt.Printf("You're %v years old now!", b.Age)
}
นี่คือ Go Playgroundที่แสดงรหัสด้านบน
ด้วยวิธีนี้ฉันสามารถสร้างอินเทอร์เฟซที่กำหนดข้อมูลมากกว่าพฤติกรรมและสามารถใช้งานได้โดยโครงสร้างใด ๆ เพียงแค่ฝังข้อมูลนั้น คุณสามารถกำหนดฟังก์ชันที่โต้ตอบกับข้อมูลที่ฝังไว้อย่างชัดเจนและไม่ทราบถึงลักษณะของโครงสร้างภายนอก และทุกอย่างจะถูกตรวจสอบในเวลารวบรวม! (วิธีเดียวที่คุณสามารถเลอะที่ฉันสามารถดูจะได้รับการฝังอินเตอร์เฟซPersonProvider
ในBob
มากกว่าคอนกรีตPerson
. มันจะรวบรวมและล้มเหลวที่รันไทม์.)
ต่อไปนี้เป็นคำถามของฉัน: นี่เป็นเคล็ดลับที่เรียบร้อยหรือฉันควรทำอย่างอื่นดี?