天天看點

第9章 面向對象—接口多态斷言

作者:菜園子dz

接口的引入

【1】代碼入門:

package main

import "fmt"

//接口的定義:定義規則、定義規範,定義某種能力:
type SayHello interface{
	sayHello()
}

//接口的實作:定義一個結構體:
//中國人:
type Chinese struct{
	
}

//實作接口的方法---》具體的實作:
func (person Chinese) sayHello(){
	fmt.Println("你好")
}

//接口的實作:定義一個結構體:
//美國人:
type American struct{
	
}

//實作接口的方法---》具體的實作:
func (person American) sayHello()  {
	fmt.Println("hi")
}

//定義一個函數:專門用來各國人打招呼的函數,接收具備SayHello接口的能力的變量:
func greet(s SayHello)  {
	s.sayHello()
}


func main(){

	c := Chinese{}
	a := American{}
	greet(c)
	greet(a)
	
}           

【2】總結:

(1)接口中可以定義一組方法,但不需要實作,不需要方法體。并且接口中不能包含任何變量。到某個自定義類型要使用的時候(實作接口的時候),再根據具體情況把這些方法具體實作出來。

(2)實作接口要實作所有的方法才是實作。

(3)Golang中的接口不需要顯式的實作接口。Golang中沒有implement關鍵字。

(Golang中實作接口是基于方法的,不是基于接口的)

例如:

A接口 a,b方法

B接口 a,b方法

C結構體 實作了 a,b方法 ,那麼C實作了A接口,也可以說實作了B接口 (隻要實作全部方法即可,和實際接口耦合性很低,比Java松散得多)

(4)接口目的是為了定義規範,具體由别人來實作即可。

接口注意事項

【1】接口本身不能建立執行個體,但是可以指向一個實作了該接口的自定義類型的變量。

// 直接用接口建立執行個體,出錯:
	// var s SayHello
	// s.sayHello()           

【2】隻要是自定義資料類型,就可以實作接口,不僅僅是結構體類型。

type integer int

func (i integer) sayHello()  {
	fmt.Println("say hi + ",i)
}

func main(){

	var i integer = 10
	s = i
	s.sayHello()
}           

【3】一個自定義類型可以實作多個接口

package main

import "fmt"

type AInterface interface{
	a()
}

type BInterface interface{
	b()
}

type Stu struct{

}

func (s Stu) a() {
	fmt.Println("this is a()")
}

func (s Stu) b() {
	fmt.Println("this is b()")
}

func main()  {
	var s Stu;
	var a AInterface = s
	var b BInterface = s
	a.a()
	b.b()
}           

【4】一個接口(比如A接口)可以繼承多個别的接口(比如B,C接口),這時如果要實作A接口,也必須将B,C接口的方法也全部實作。

package main

import "fmt"

type CInterface interface{
	c()
}

type BInterface interface{
	b()
}

type AInterface interface{
	CInterface
	BInterface
	a()
}

type Stu struct{

}

func (s Stu) a() {
	fmt.Println("a")
}

func (s Stu) b()  {
	fmt.Println("b")
}

func (s Stu) c() {
	fmt.Println("c")
}



func main()  {
	var s Stu
	var a AInterface = s
	a.a()
	a.b()
	a.c()
}           

【5】interface類型預設是一個指針(引用類型),如果沒有對interface初始化就使用,那麼會輸出nil

【6】空接口沒有任何方法,是以可以了解為所有類型都實作了空接口,也可以了解為我們可以把任何一個變量賦給空接口。

type E interface {

}

func main()  {
	
	var e E = s
	fmt.Println(e)
	var e2 interface{} = s
	fmt.Println(e2)
	var num float32 = 9.99
	var e3 interface{} = num
	fmt.Println(e3)
}           

多态

【1】基本介紹

變量(執行個體)具有多種形态。面向對象的第三大特征,在Go語言,多态特征是通過接口實作的。可以按照統一的接口來調用不同的實作。這時接口變量就呈現不同的形态。

【2】案例:

//定義一個函數:專門用來各國人打招呼的函數,接收具備SayHello接口的能力的變量:
func greet(s SayHello)  {
	s.sayHello()
}           

【3】接口展現多态特征

1) 多态參數: s叫多态參數

第9章 面向對象—接口多态斷言

2) 多态數組 :

比如:定義SayHello數組,存放中國人結構體、美國人結構體

var arr [3]SayHello
	arr[0] = American{"Rose"}
	arr[1] = Chinese{"菜園子"}
	arr[2] = Chinese{"蜘蛛俠"}

	fmt.Println(arr)           

斷言

【1】什麼是斷言?

Go語言裡面有一個文法,可以直接判斷是否是該類型的變量: value, ok := element.(T),這裡value就是變量的值,ok是一個bool類型,element是interface變量,T是斷言的類型。

【2】斷言的案例引入:

package main

import "fmt"

type SayHello interface{
	sayHello()
}

type Chinese struct{
	name string
}

func (person Chinese) sayHello(){
	fmt.Println("你好")
}

func (person Chinese) niuYangGe(){
	fmt.Println("扭秧歌")
}

type American struct{
	name string
}

func (person American) sayHello(){
	fmt.Println("hi")
}

//定義一個函數:專門用來各國人打招呼的函數,接收具備SayHello接口的能力的變量:
func greet(s SayHello)  {
	s.sayHello()
	//斷言:
	//看s是否能轉成Chinese類型并且賦給ch變量,flag是判斷是否轉成功
	var ch Chinese = s.(Chinese)
	ch.niuYangGe()
	fmt.Println("打招呼")
}


func main()  {
	c := Chinese{}
	greet(c)

	// a := American{}
	// greet(a)
}           

解決第二個傳回值問題:

//定義一個函數:專門用來各國人打招呼的函數,接收具備SayHello接口的能力的變量:
func greet(s SayHello)  {
	s.sayHello()
	//斷言:
	//看s是否能轉成Chinese類型并且賦給ch變量,flag是判斷是否轉成功
	// var ch Chinese = s.(Chinese)
	// ch.niuYangGe()

	ch,flag := s.(Chinese)
	if flag == true {
		ch.niuYangGe()
	} else {
		fmt.Println("美國人不會扭秧歌")
	}

	fmt.Println("打招呼")
}           

【3】Type Switch 的基本用法

Type Switch 是 Go 語言中一種特殊的 switch 語句,它比較的是類型而不是具體的值。它判斷某個接口變量的類型,然後根據具體類型再做相應處理。

func (person American) disco() {
	fmt.Println("野狼disco")
}
//定義一個函數:專門用來各國人打招呼的函數,接收具備SayHello接口的能力的變量:
func greet(s SayHello)  {
	s.sayHello()
	//斷言:
	//看s是否能轉成Chinese類型并且賦給ch變量,flag是判斷是否轉成功
	// var ch Chinese = s.(Chinese)
	// ch.niuYangGe()

	// ch,flag := s.(Chinese)
	// if flag == true {
	// 	ch.niuYangGe()
	// } else {
	// 	fmt.Println("美國人不會扭秧歌")
	// }

	switch s.(type) {
		case Chinese:
			ch := s.(Chinese)
			ch.niuYangGe()
		case American:
			am := s.(American)
			am.disco()
	}
	

	fmt.Println("打招呼")
}           

源碼位址:「連結」

參考個人部落格平台:cyz

繼續閱讀