Interface
Interface là gì?
Interface định nghĩa tập hợp các method signature mà một type phải thực hiện. Điểm đặc biệt của Go: implicit implementation — không cần khai báo "implements".
type Animal interface {
Sound() string
Name() string
Move() string
}
// Dog tự động implement Animal vì có đủ 3 method
type Dog struct{ Breed string }
func (d Dog) Sound() string { return "Gâu gâu" }
func (d Dog) Name() string { return "Chó " + d.Breed }
func (d Dog) Move() string { return "Chạy bằng 4 chân" }
// Bird cũng implement Animal
type Bird struct{}
func (b Bird) Sound() string { return "Chíu chíu" }
func (b Bird) Name() string { return "Chim" }
func (b Bird) Move() string { return "Bay" }
Dùng Interface làm tham số
func introduce(a Animal) {
fmt.Printf("%s: %q | %s\n", a.Name(), a.Sound(), a.Move())
}
introduce(Dog{Breed: "Husky"}) // Chó Husky: "Gâu gâu" | Chạy bằng 4 chân
introduce(Bird{}) // Chim: "Chíu chíu" | Bay
Interface phổ biến trong stdlib
// io.Reader — bất cứ thứ gì có thể đọc từ
type Reader interface {
Read(p []byte) (n int, err error)
}
// io.Writer — bất cứ thứ gì có thể ghi vào
type Writer interface {
Write(p []byte) (n int, err error)
}
// fmt.Stringer — định nghĩa cách print
type Stringer interface {
String() string
}
// Implement Stringer để fmt.Println hiểu kiểu của bạn
func (d Dog) String() string {
return fmt.Sprintf("Dog(%s)", d.Breed)
}
Interface lồng nhau
type ReadWriter interface {
Reader // embed Reader interface
Writer // embed Writer interface
}
// Type implement ReadWriter phải có cả Read() lẫn Write()
Empty interface — interface{}
// interface{} (hoặc any từ Go 1.18) chấp nhận mọi kiểu
func printAny(v interface{}) {
fmt.Printf("%T: %v\n", v, v)
}
printAny(42)
printAny("hello")
printAny([]int{1, 2, 3})
// Type assertion để lấy lại kiểu gốc
func process(v interface{}) {
if s, ok := v.(string); ok {
fmt.Println("String:", strings.ToUpper(s))
}
}
example.go
package main
import (
"fmt"
"math"
"sort"
)
type Shape interface {
Area() float64
Perimeter() float64
Name() string
}
type Rectangle struct{ Width, Height float64 }
type Circle struct{ Radius float64 }
type Triangle struct{ A, B, C float64 }
func (r Rectangle) Area() float64 { return r.Width * r.Height }
func (r Rectangle) Perimeter() float64 { return 2 * (r.Width + r.Height) }
func (r Rectangle) Name() string { return "Hình chữ nhật" }
func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius }
func (c Circle) Perimeter() float64 { return 2 * math.Pi * c.Radius }
func (c Circle) Name() string { return "Hình tròn" }
func (t Triangle) Area() float64 {
s := (t.A + t.B + t.C) / 2
return math.Sqrt(s * (s - t.A) * (s - t.B) * (s - t.C))
}
func (t Triangle) Perimeter() float64 { return t.A + t.B + t.C }
func (t Triangle) Name() string { return "Tam giác" }
func printShape(s Shape) {
fmt.Printf("%-20s Diện tích: %8.2f Chu vi: %8.2f\n",
s.Name(), s.Area(), s.Perimeter())
}
func main() {
shapes := []Shape{
Rectangle{Width: 5, Height: 3},
Circle{Radius: 4},
Triangle{A: 3, B: 4, C: 5},
Rectangle{Width: 10, Height: 2},
}
for _, s := range shapes {
printShape(s)
}
// Sắp xếp theo diện tích
sort.Slice(shapes, func(i, j int) bool {
return shapes[i].Area() < shapes[j].Area()
})
fmt.Println("\nSắp xếp theo diện tích:")
for _, s := range shapes {
fmt.Printf(" %s: %.2f\n", s.Name(), s.Area())
}
}