1. 程式人生 > >interface 介面

interface 介面

Interface

1. 概述
  Interface 是一組抽象方法(未具體實現的方法/僅包含方法名引數返回值的方法)的集合,有點像但又不同於其他程式語言中的 interface 。
  如果實現了 interface 中的所有方法,即該類/物件就實現了該介面

2. interface 型別
  格式:
type interfaceName interface {
  //方法列表
}
  注:
  a. interface 可以被任意物件實現,一個型別/物件也可以實現多個 interface
  b. 方法不能過載,如 eat() eat(s string) 不能同時存在

3. interface 值
  宣告為 interface 型別的變數,可以儲存任何實現了 interface 中所有方法的型別的變數(物件)
  注:類的值型別傳遞方法會自動生成對應的引用型別傳遞方法,反之不成立

4. interface 組合

  將一個 interface1 嵌入到另一個 interface2 的宣告中
  其作用相當於把 interface1 的函式包含到 interface2 中,但是組合中不同有重複的方法
  注:
  a. 只要兩個介面中的方法列表相同(與順序無關),即為相同的介面,可以相互賦值
  b. interface1 的方法列表屬於另一個 interface2 的方法列表的子集,interface2 可以賦值給 interface1,反之不成立(因為方法缺失),interface2 中的方法會覆蓋 interface1 中同名的方法
  c. 可以嵌入包中的 interface

5. interface 查詢

  通過查詢可以判斷介面它指向的物件是否為某個型別
  通過查詢可以將原本為子集的 interface1 轉為 interface2 型別,即 interface1 就可以呼叫原本屬於 interface2 獨有的方法
  常見用法:
  if varName2, ok := varName1.(interface2|typeName); ok {
    //此時 varName2 的型別由 interface1 轉為 interface2,或者 varName1 不是 typeName 型別的變數
  } else {
    //不能轉換 interface,或者 varName1 不是 typeName 型別的變數
  }
  注:
  a. varName2 儲存 varName1 值,varName1 為 interface 變數, () 中為型別
  b. varName.(type) 用於判斷型別,不能用於 switch 外的邏輯中,此處的 type 關鍵字

示例程式:
package main

import "fmt"

type Person struct {
	name string
	age int
}

func (p Person) printMsg() {
	fmt.Printf("I am %s, and my age is %d.\n", p.name, p.age)
}

func (p Person) eat(s string) {
	fmt.Printf("%s is eating %s ...\n", p.name, s)
}

func (p Person) drink(s string) {
	fmt.Printf("%s is drinking %s ...\n", p.name, s)
}

type People interface {
	printMsg()
	PeopleEat    //組合
	PeopleDrink
	//eat() //不能出現重複的方法
}
/*
//與上面等價
type People interface {
	printMsg()
	eat()
	drink()
}
*/
type PeopleDrink interface {
	drink(s string)
}

type PeopleEat interface {
	eat(s string)
}

type PeopleEatDrink interface {
	eat(s string)
	drink(s string)
}

//以上 Person 類[型]就實現了 People/PeopleDrink/PeopleEat/PeopleEatDrink interface 型別

type Foodie struct {
	name string
}

func (f Foodie) eat(s string) {
	fmt.Printf("I am foodie, %s. My favorite food is the %s.\n", f.name, s)
}

//Foodie 類實現了 PeopleEat interface 型別

func main() {
	//定義一個 People interface 型別的變數p1
	var p1 People
	p1 = Person{"Rain", 23}
	p1.printMsg()           //I am Rain, and my age is 23.
	p1.drink("orange juice")//print result: Rain is drinking orange juice

	//同一類可以屬於多個 interface, 只要這個類實現了這個 interface中的方法
	var p2 PeopleEat
	p2 = Person{"Sun", 24}
	p2.eat("chaffy dish")//print result: Sun is eating chaffy dish ...

	//不同類也可以實現同一個 interface
	var p3 PeopleEat
	p3 = Foodie{"James"}
	p3.eat("noodle")//print result: I am foodie, James. My favorite food is the noodle

	//interface 賦值
	p3 = p1  //p3 中的方法會被 p1 中的覆蓋
	p3.eat("noodle")
	/************************************/
	/*print result                      */
	/*Rain is eating noodle ...         */
	/************************************/

	//interface 查詢
	//將(子集) PeopleEat 轉為 People 型別
	if p4, ok := p2.(People); ok {
		p4.drink("water") //呼叫 People interface 中有而 PeopleEat 中沒有的方法
		fmt.Println(p4)
	}
	/************************************/
	/*print result                      */
	/*Sun is drink water ...            */
	/*{Sun 24}                          */
	/************************************/

	//查詢 p2 是否為 Person 型別變數
	if p5, ok := p2.(Person); ok {
		fmt.Println(p5, "type is Person")
		p5.drink("***")  //此時也可以呼叫 Person 所有的方法
	}
	/************************************/
	/*print result                      */
	/*{Sun 24} type is Person           */
	/*Sun is drink *** ...              */
	/************************************/

	var p6 PeopleEat = Foodie{"Tom"}

	if p7, ok := p6.(People); ok {
		fmt.Println(p7)
	} else {
		fmt.Println("Error: can not convert")
	}
	//result: Error: can not convert

	if p8, ok := p6.(Foodie); ok {
		fmt.Println(p8, "type is Foodie")
	}
	//result: {Tom} type is Foodie
}

執行結果:
I am Rain, and my age is 23.
Rain is drinking orange juice ...
Sun is eating chaffy dish ...
I am foodie, James. My favorite food is the noodle.
Rain is eating noodle ...
Sun is drinking water ...
{Sun 24}
{Sun 24} type is Person
Sun is drinking *** ...
Error: can not convert
{Tom} type is Foodie


6. 空介面
  空介面,無方法,即 interface{},可以代表任何型別,有點類似於 java 中的 Object 類
  可以作為任何形參和返回型別,mixed
  例:
//interface{}
var i interface{} = 100
var s interface{} = "hello"
fmt.Printf("i = %d, s = %s\n", i, s)
s = i
fmt.Printf("i = %d, s = %d\n", i, s)
  結果:
i = 100, s = hello

i = 100, s = 100