day09 介面

染指未来發表於2024-07-02

什麼是介面

  • 即:將一些共性方法集合在一起
  • 方法的集合,不需要方法的具體內容
package main

import "fmt"

// 定義介面 使用 interface. 結合 struct 結構體使用
type USB interface {
	input()  // 輸入 方法
	output() // 輸出 方法
}
type Mouse struct {
	name string
}

type KeyBord struct {
	name string
}

// 實現 介面的全部方法,就代表實現類這個介面
func (m Mouse) input() {
	fmt.Println(m.name, "滑鼠輸入")

}
func (m Mouse) output() {
	fmt.Println(m.name, "滑鼠輸出")

}
func (k KeyBord) input() {
	fmt.Println(k.name, "鍵盤輸入")

}
func (k KeyBord) output() {
	fmt.Println(k.name, "鍵盤輸入")

}

func realizeUsb(usb USB) {
	usb.input()
	usb.output()
}

func main() {
	/*
		go中的介面
			- 什麼是介面? 即:將一些共性方法集合在一起
			- 介面是:方法的集合,不需要方法的具體內容
	*/
	// 透過傳入`介面` 來實現呼叫
	mouse := Mouse{name: "羅技"}
	// realizeUsb 的引數 是介面型別,如果一個結構體實現這個介面的所有方法,則結構體就是介面型別
	realizeUsb(mouse)
	keyboard := KeyBord{name: "鐳射"}
	realizeUsb(keyboard)

	// 定義高階型別
	var usb USB
	usb = mouse
	// 只能呼叫usb介面中的方法,不能呼叫 mouse 結構體中的屬性
	// usb.name // usb.name undefined (type USB has no field or method name)
	usb.input()

}

go 空介面

  • 所有結構體都實現類空介面個,空介面可以儲存任何型別
  • interface {} == any
package main

import "fmt"

// 定義空介面,實現包容萬物
type EmptyInterface interface {
}

type DogEmptyStruct struct {
	name string
}

// 定義空介面實現方法
func emptyInterfaceFunc(ei EmptyInterface) {
	fmt.Printf("空介面實現函式。【引數:%v  ----  型別:%T】\n", ei, ei) // main.DogEmptyStruct
}

// 萬能介面. 空介面作為函式的引數// main.DogEmptyStruct
func emptyInterfaceFunc2(universalInterface interface{}) {
	fmt.Printf("萬能介面。【引數:%v  ----  型別:%T】\n", universalInterface, universalInterface)

}
func main() {
	/*空介面*/
	// 所有結構體都實現類空介面個,空介面可以儲存任何型別
	// interface {} == any

	var dogEmpty = DogEmptyStruct{name: "小雞毛"}
	emptyInterfaceFunc(dogEmpty)
	fmt.Println("-----")
	//
	var a1 EmptyInterface = DogEmptyStruct{name: "小雞毛"}
	fmt.Printf("a1 【引數:%v  ----  型別:%T】\n", a1, a1) // 【引數:{小雞毛}  ----  型別:main.DogEmptyStruct】

	var a2 EmptyInterface = 1
	fmt.Printf("a2 【引數:%v  ----  型別:%T】\n", a2, a2) // 【引數:1  ----  型別:int】

	var a3 EmptyInterface = "string"
	fmt.Printf("a3 【引數:%v  ----  型別:%T】\n", a3, a3) // 【a3 【引數:string  ----  型別:string】

	fmt.Println(a1, a2, a3)
	fmt.Println("萬能引數,空介面-----")
	emptyInterfaceFunc2(1)
	emptyInterfaceFunc2("string")
	emptyInterfaceFunc2(make([]string, 10))

	fmt.Println("空介面對map和slice的使用-----")
	map1 := make(map[string]interface{})
	map2 := make(map[string]any)
	fmt.Printf("map1 【型別:%T】\n", map1) // 【型別:map[string]interface {}】

	fmt.Printf("map2 【型別:%T】\n", map2) // 【型別:map[string]interface {}】

	// 空介面能 接收任何型別的引數
	map1["a1"] = a1
	map1["a2"] = a2
	map1["a3"] = a3
	fmt.Println(map1) // map[a1:{小雞毛} a2:1 a3:string]

}

介面型別

package main

import "fmt"

type MyStruct struct {
	code int
}

type MyInterface interface {
	myInterfaceFunc()
}

func (msc *MyStruct) myInterfaceFunc() interface{} {
	return interface{}(msc.code)
}
func test(msc MyStruct) {
	ret := msc.myInterfaceFunc()
	fmt.Printf("型別:%T\n", ret)
	fmt.Printf("記憶體地址:%p\n", &ret)
}

func main() {
	ms1 := MyStruct{code: 1}
	test(ms1)
	ms2 := MyStruct{code: 2}
	test(ms2)

	var any interface{}
	fmt.Printf("any型別:%T\n", any)
	fmt.Printf("any記憶體地址:%p\n", &any)
	any2 := any
	any3 := any
	fmt.Printf("any2型別:%T\n", any2)
	fmt.Printf("any2記憶體地址:%p\n", &any2)
	fmt.Printf("any3記憶體地址:%p\n", &any3)
	any = 42
	// 動態型別斷言
	if val, ok := any.(int); ok {
		fmt.Println("Value is an integer:", val)
	} else {
		fmt.Println("Value is not an integer")
	}
}

介面巢狀

package main

import "fmt"

type AA interface {
	test1()
}

type BB interface {
	test2()
}

// 定義介面CC : 如果實現CC介面,需要實現test1()/test2()/test3() 三個方法
type CC interface {
	// 巢狀 介面
	AA // 匯入AA介面中的方法
	BB
	test3()
}

// 編寫一個結構體 , 實現CC
type Dog7 struct {
}

// 函式+結構體引數+介面中定義的函式名
func (d Dog7) test1() {
	fmt.Println("test1")
}
func (d Dog7) test2() {
	fmt.Println("test2")

}
func (d Dog7) test3() {
	fmt.Println("test3")

}
func main() {
	/* 介面的巢狀 */

	// 結構體例項化物件,呼叫介面 AA / BB / CC 三個方法
	var dog Dog7 = Dog7{}
	dog.test1()
	dog.test2()
	dog.test3()

	// 因為CC介面巢狀了 AA 和 BB 介面。可以定義 某個變數的型別為介面型別。將結構體物件賦值給 這個變數。這個變數就能實現 test1/test2/test3 三個方法
	var c CC = Dog7{} // 向上轉型後只能呼叫自己的方法
	c.test3()
	c.test2()
	c.test1()
	// 因為CC介面巢狀了 AA 和 BB 介面。可以定義 某個變數的型別為介面型別。將結構體物件賦值給 這個變數。這個變數就能實現 test1/test2/test3 三個方法

	var a AA = Dog7{}
	//a.test3() // 向上轉型後只能呼叫自己的方法
	//a.test2() // 向上轉型後只能呼叫自己的方法
	a.test1()

}

介面斷言

  • 定義:檢查一個介面的變數是不是符合預期呼叫/值
  • 被斷言的物件必須是介面型。否則會報錯
  • 格式: t,ok:=i.(T) 【t:就是i介面是T型別的,i:介面,T:型別】
package main

import "fmt"

func main() {
	/*
		介面斷言
			- 定義:檢查一個介面的變數是不是符合預期呼叫/值
			- 被斷言的物件必須是介面型。否則會報錯
			- 格式: t,ok:=i.(T) 【t:就是i介面是T型別的,i:介面,T:型別】
	*/

	assertString("123") // 斷言成功,則無異常
	//assertString(123)   // 斷言失敗就會丟擲異常,停止程式【panic: interface conversion: interface {} is int, not string 】
	assertInt("1")
	assertInt(true)
	assertInt(1)
}

// 判斷一個變數是不是字串型別
func assertString(i interface{}) {
	s := i.(string)
	fmt.Println(s)
}

// 斷言失敗不希望程式停止
func assertInt(i any) {
	i, ok := i.(int)
	fmt.Println(i, ok)
	if ok {
		fmt.Println("int型別")
	} else {
		fmt.Println("非int型別")
	}
}

相關文章