介面
Go 語言介面:Duck Typing、方法集合。
Interface
介面是方法集合的藍圖。
- 指定一組方法,但不實作
- 不宣告變數
- 不定義方法
type <interface_name> interface {
// Method signatures
}基本範例
type Speaker interface {
Speak() string
}
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return "Woof!"
}
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return "Meow!"
}
func MakeSound(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
dog := Dog{Name: "Buddy"}
cat := Cat{Name: "Whiskers"}
MakeSound(dog) // Woof!
MakeSound(cat) // Meow!
}Duck Typing
看行為,不看身分
- 只要物件能執行需要的方法/行為,就可以使用
- 不需要明確繼承或實作介面
- 關注「能做什麼」,而非「是什麼」
這種設計讓程式更靈活,但需要小心處理執行期錯誤。
// 任何有 Write 方法的類型都滿足 io.Writer
type Writer interface {
Write(p []byte) (n int, err error)
}
// 自訂類型
type ConsoleWriter struct{}
func (cw ConsoleWriter) Write(p []byte) (n int, err error) {
return fmt.Println(string(p))
}
// 可以當作 io.Writer 使用
var w io.Writer = ConsoleWriter{}Empty Interface
空介面 interface{} 可以持有任何型別的值。
func PrintAnything(v interface{}) {
fmt.Printf("Type: %T, Value: %v\n", v, v)
}
func main() {
PrintAnything(42)
PrintAnything("hello")
PrintAnything(true)
PrintAnything([]int{1, 2, 3})
}Go 1.18+ 可以使用
any 作為 interface{} 的別名。Type Assertion
型別斷言用於從介面取得具體型別。
var i interface{} = "hello"
// 基本斷言(失敗會 panic)
s := i.(string)
// 安全斷言(推薦)
s, ok := i.(string)
if ok {
fmt.Println("String:", s)
}
// 斷言失敗不會 panic
n, ok := i.(int)
if !ok {
fmt.Println("Not an int")
}Type Switch
用於處理多種可能的型別。
func describe(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Integer: %d\n", v*2)
case string:
fmt.Printf("String: %q (len=%d)\n", v, len(v))
case bool:
fmt.Printf("Boolean: %t\n", v)
case []int:
fmt.Printf("Slice of int: %v\n", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}Interface Composition
介面可以組合其他介面。
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// 組合介面
type ReadWriter interface {
Reader
Writer
}Type List
Ordered Type:也支援 <, <=, >, >= 運算符。
type Ordered interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
~float32 | ~float64 |
~string
}
func Min[T Ordered](a, b T) T {
if a < b {
return a
}
return b
}常見介面
Stringer
type Stringer interface {
String() string
}
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}Error
type error interface {
Error() string
}
type MyError struct {
Code int
Message string
}
func (e MyError) Error() string {
return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}nil
在 error 位置回傳 nil 表示沒有錯誤。
func doSomething() error {
// 成功時回傳 nil
return nil
}
// 介面值為 nil 的情況
var s Speaker // nil
if s == nil {
fmt.Println("s is nil")
}介面值包含型別和值兩部分。只有當兩者都是 nil 時,介面值才等於 nil。
var p *Dog = nil
var s Speaker = p
// s != nil(型別不是 nil)
if s == nil {
fmt.Println("this won't print")
}