1. 程式人生 > >Go學習(11):介面

Go學習(11):介面

介面

1.1 什麼是介面?

面向物件世界中的介面的一般定義是“介面定義物件的行為”。它只指定物件應該做什麼。實現這種行為的方法(實現細節)是針對物件的。

在Go中,介面是一組方法簽名。當型別為介面中的所有方法提供定義時,它被稱為實現介面。它與OOP非常相似。介面指定了型別應該具有的方法,型別決定了如何實現這些方法。

它把所有的具有共性的方法定義在一起,任何其他型別只要實現了這些方法就是實現了這個介面

介面定義了一組方法,如果某個物件實現了某個介面的所有方法,則此物件就實現了該介面。

1.2 介面的定義語法

定義介面

/* 定義介面 */
type
interface_name interface { method_name1 [return_type] method_name2 [return_type] method_name3 [return_type] ... method_namen [return_type] } /* 定義結構體 */ type struct_name struct { /* variables */ } /* 實現介面方法 */ func (struct_name_variable struct_name) method_name1() [return_type] { /* 方法實現 */
} ... func (struct_name_variable struct_name) method_namen() [return_type] { /* 方法實現*/ }

示例程式碼:

package main

import (
    "fmt"
)

type Phone interface {
    call()
}

type NokiaPhone struct {
}

func (nokiaPhone NokiaPhone) call() {
    fmt.Println("I am Nokia, I can call you!")
}

type IPhone struct
{ } func (iPhone IPhone) call() { fmt.Println("I am iPhone, I can call you!") } func main() { var phone Phone phone = new(NokiaPhone) phone.call() phone = new(IPhone) phone.call() }

執行結果:

I am Nokia, I can call you!
I am iPhone, I can call you!
  • interface可以被任意的物件實現
  • 一個物件可以實現任意多個interface
  • 任意的型別都實現了空interface(我們這樣定義:interface{}),也就是包含0個method的interface

1.3 interface值

package main

import "fmt"

type Human struct {
	name  string
	age   int
	phone string
}
type Student struct {
	Human  //匿名欄位
	school string
	loan   float32
}
type Employee struct {
	Human   //匿名欄位
	company string
	money   float32
} //Human實現Sayhi方法
func (h Human) SayHi() {
	fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
} //Human實現Sing方法
func (h Human) Sing(lyrics string) {
	fmt.Println("La la la la...", lyrics)
} //Employee重寫Human的SayHi方法
func (e Employee) SayHi() {
	fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
		e.company, e.phone) //Yes you can split into 2 lines here.
}

// Interface Men被Human,Student和Employee實現
// 因為這三個型別都實現了這兩個方法
type Men interface {
	SayHi()
	Sing(lyrics string)
}

func main() {
	mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
	paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
	sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
	Tom := Employee{Human{"Sam", 36, "444-222-XXX"}, "Things Ltd.", 5000}
	//定義Men型別的變數i
	var i Men
	//i能儲存Student
	i = mike
	fmt.Println("This is Mike, a Student:")
	i.SayHi()
	i.Sing("November rain")
	//i也能儲存Employee
	i = Tom
	fmt.Println("This is Tom, an Employee:")
	i.SayHi()
	i.Sing("Born to be wild")
	//定義了slice Men
	fmt.Println("Let's use a slice of Men and see what happens")
	x := make([]Men, 3)
	//T這三個都是不同型別的元素,但是他們實現了interface同一個介面
	x[0], x[1], x[2] = paul, sam, mike
	for _, value := range x {
		value.SayHi()
	}
}

執行結果:

	This is Mike, a Student:
	Hi, I am Mike you can call me on 222-222-XXX
	La la la la... November rain
	This is Tom, an Employee:
	Hi, I am Sam, I work at Things Ltd.. Call me on 444-222-XXX
	La la la la... Born to be wild
	Let's use a slice of Men and see what happens
	Hi, I am Paul you can call me on 111-222-XXX
	Hi, I am Sam, I work at Golang Inc.. Call me on 444-222-XXX
	Hi, I am Mike you can call me on 222-222-XXX

那麼interface裡面到底能存什麼值呢?如果我們定義了一個interface的變數,那麼這個變數裡面可以存實現這個interface的任意型別的物件。例如上面例子中,我們定義了一個Men interface型別的變數m,那麼m裡面可以存Human、Student或者Employee值

當然,使用指標的方式,也是可以的

但是,介面物件不能呼叫實現物件的屬性

interface函式引數

interface的變數可以持有任意實現該interface型別的物件,這給我們編寫函式(包括method)提供了一些額外的思考,我們是不是可以通過定義interface引數,讓函式接受各種型別的引數

嵌入interface

package main

import "fmt"

type Human interface {
	Len()
}
type Student interface {
	Human
}

type Test struct {
}

func (h *Test) Len() {
	fmt.Println("成功")
}
func main() {
	var s Student
	s = new(Test)
	s.Len()
}

執行結果:

成功

示例程式碼:

package test

import (
	"fmt"
)

type Controller struct {
	M int32
}

type Something interface {
	Get()
	Post()
}

func (c *Controller) Get() {
	fmt.Print("GET")
}

func (c *Controller) Post() {
	fmt.Print("POST")
}
package main

import (
	"fmt"
	"test"
)

type T struct {
	test.Controller
}

func (t *T) Get() {
	//new(test.Controller).Get()
	fmt.Print("T")
}
func (t *T) Post() {
	fmt.Print("T")
}
func main() {
	var something test.Something
	something = new(T)
	var t T
	t.M = 1
	//	t.Controller.M = 1
	something.Get()
}

示例程式碼:

T

Controller實現了所有的Something介面方法,當結構體T中呼叫Controller結構體的時候,T就相當於Java中的繼承,T繼承了Controller,因此,T可以不用重寫所有的Something介面中的方法,因為父構造器已經實現了介面。

如果Controller沒有實現Something介面方法,則T要呼叫Something中方法,就要實現其所有方法。

如果something = new(test.Controller)則呼叫的是Controller中的Get方法。

T可以使用Controller結構體中定義的變數

總結

介面物件不能呼叫介面實現物件的屬性