Interface дэвшилтэт хэрэглээ
Өмнөх хичээлд interface-ийн үндсийг судалсан. Одоо interface-ийг илүү нарийн ашиглах аргуудыг сурна. Эдгээр техникүүдийг мэдсэнээр та Go-ийн хамгийн хүчирхэг хэлбэрийн нэгийг бүрэн эзэмшинэ.
Interface нэгтгэх (Embedding)
Go-д нэг interface-ийг нөгөөдөө оруулж болдог. Үүнийг interface embedding гэнэ.
package main
import "fmt"
type Reader interface {
Read() string
}
type Writer interface {
Write(text string)
}
// Reader ба Writer-ийг нэгтгэсэн шинэ interface
type ReadWriter interface {
Reader
Writer
}
type File struct {
content string
}
func (f *File) Read() string {
return f.content
}
func (f *File) Write(text string) {
f.content = text
}
func process(rw ReadWriter) {
rw.Write("Сайн уу, Go!")
fmt.Println(rw.Read())
}
func main() {
f := &File{}
process(f)
}
File struct нь Read() болон Write() хоёуланг хэрэгжүүлсэн тул ReadWriter interface-д нийцдэг.
Type Assertion
Interface-ийн цаана ямар concrete тип байгааг шалгахдаа type assertion ашигладаг.
package main
import "fmt"
type Animal interface {
Sound() string
}
type Dog struct{ Name string }
type Cat struct{ Name string }
func (d Dog) Sound() string { return "Хав хав" }
func (c Cat) Sound() string { return "Миаа" }
func describe(a Animal) {
// Хоёр утга буцаадаг хэлбэр — аюулгүй
if dog, ok := a.(Dog); ok {
fmt.Printf("Энэ нохой: %s\n", dog.Name)
return
}
if cat, ok := a.(Cat); ok {
fmt.Printf("Энэ муур: %s\n", cat.Name)
return
}
fmt.Println("Тодорхойгүй амьтан")
}
func main() {
animals := []Animal{
Dog{Name: "Бурхан"},
Cat{Name: "Цагаан"},
}
for _, a := range animals {
describe(a)
}
}
a.(Dog) гэдэг нь "a нь Dog мөн үү?" гэж асуудаг. ok нь true байвал таарсан гэсэн үг.
Type Switch
Олон тип шалгах үед type switch хэлбэр хамаагүй цэвэр харагддаг:
package main
import "fmt"
func typeCheck(v interface{}) {
switch val := v.(type) {
case int:
fmt.Printf("Бүхэл тоо: %d\n", val)
case string:
fmt.Printf("Мөр: %s\n", val)
case bool:
fmt.Printf("Логик утга: %v\n", val)
case []int:
fmt.Printf("int slice, урт: %d\n", len(val))
default:
fmt.Printf("Тодорхойгүй тип: %T\n", val)
}
}
func main() {
typeCheck(42)
typeCheck("Монгол")
typeCheck(true)
typeCheck([]int{1, 2, 3})
typeCheck(3.14)
}
v.(type) бичиглэл нь зөвхөн switch дотор ажилладаг онцлог байдал юм.
Empty Interface — any
Go-д interface{} буюу Go 1.18-с хойш any гэдэг нь ямар ч утга хүлээн авдаг:
package main
import "fmt"
func printAnything(values ...any) {
for _, v := range values {
fmt.Printf("Утга: %v, Тип: %T\n", v, v)
}
}
func main() {
printAnything(1, "хоёр", true, 3.14, []string{"a", "b"})
}
any нь маш уян хатан боловч хэт их ашиглавал код ойлгоход хэцүү болдог. Шаардлагагүй тохиолдолд конкрет тип ашиглах нь дээр.
Interface хэрэгжүүлэлт шалгах
Compile хийх үед interface-ийг зөв хэрэгжүүлсэн эсэхийг шалгах нэг арга:
package main
type Stringer interface {
String() string
}
type Person struct {
Name string
}
func (p Person) String() string {
return p.Name
}
// Compile-ийн үед шалгалт — энэ мөр ажиллахгүй код боловч алдаа барьдаг
var _ Stringer = Person{}
func main() {}
var _ Stringer = Person{} гэдэг нь "Person нь Stringer-ийг хэрэгжүүлж байгаа уу?" гэж compile хийх үед шалгадаг. Хэрэгжүүлээгүй бол алдаа гарна.
Дараагийн хичээлд:
Go-д алдааг хэрхэн зохицуулах вэ — error interface болон алдаа буцаах хэв маягийг сурна. Энэ нь Go хэлний хамгийн өвөрмөц онцлогуудын нэг юм.