Go語言的接口interface、struct和組合、繼承

Go語言的interface概念相對於C++中的基類,經過interface來實現多態功能。函數

在C++中,當須要實現多態功能時,步驟是首先定義一個基類,該基類使用虛函數或者純虛函數抽象了全部子類會用到的共同的最基本的成員函數,以後子類繼承該基類,而後每一個派生類自定義本身的虛函數實現。最後在使用基類指針或者引用的地方傳入派生類,程序根據具體傳入的對象來調用對象的函數。指針

在Go中,定義一個interface類型,該類型說明了它有哪些方法,這就完成了相似C++中的基類定義,而後在其餘的函數中,將該interface類型做爲函數的形參,任意一個實現了interface類型的實參都能做爲該interface的實例對象。interface類型和做爲interface類型的實參對象之間就至關於存在繼承關係,或者說叫實現接口(Java說法),但這種繼承關係(實現接口)是隱式的(自動的),也即咱們無需主動說明(顯式implements實現)該實參類型是某interface類型的派生類,代碼以下:對象

type base interface { //相似基類定義
	virtualfunc() int //相似虛函數抽象定義
}

type der1 int //相似派生類1定義

func (der1) virtualfunc() int { //相似派生類1虛函數具體實現
	fmt.Printf("I'm der1\n")
	return 1
}

type der2 struct { //相似派生類2定義
	//nothing
}

func (der2) virtualfunc() int { //相似派生類2虛函數具體實現
	fmt.Printf("I'm der2\n")
	return 2
}

func somefunc(b base) { //做爲某個函數的形參
	b.virtualfunc()
}

上述代碼中base是interface類型,b做爲somefunc( )函數的形參,由於base接口類型要求實現virtualfunc( )函數,而der1和der2都實現了該函數,由於der1和der2自動是base的派生類,在somefunc( )函數中,要求base類型的實參時,能夠用der1或者der2的實例對象傳入,這就實現了不一樣類型不一樣行爲,也即多態。這是Go實現面向對象特性的一種特殊方法,並非經過類和繼承來完成的,Go也沒有繼承這種功能。blog

上面的代碼並無說明interface的所有特性,還有一些說明以下:繼承

  1. 實現某個接口的類型(如上面的der2)能夠有其餘的方法。這正如派生類還能夠額外增長基類並無的成員函數同樣,但增長的函數不是接口中的部分。
  2. 一個類型能夠實現多個接口。這相似於C++的多繼承,一個派生類能夠當作多種基類來使用。

從somefunc( )函數中的形實參結合能夠看到,咱們能定義一個interface類型的變量,並用一個「派生類」去初始化或者賦值,代碼以下:接口

func main() {
	var baseobj base

	var d1 der1
	baseobj = d1
	somefunc(baseobj)

	var d2 der2
	baseobj = d2
	somefunc(baseobj)
}

上面代碼中,第2行是定義了一個默認初始化的interface base類型對象,第5行和第9行代碼則是用兩個「派生類」去賦值interface base類型對象。運行結果以下:seo

I'm der1
I'm der2

 

Go中沒有繼承的功能,它是經過接口來實現相似功能,Go中還有一種叫作組合的概念,以下:class

package main

import (
	"fmt"
)

type Base struct {
	// nothing
}

func (b *Base) ShowA() {
	fmt.Println("showA")
	b.ShowB()
}
func (b *Base) ShowB() {
	fmt.Println("showB")
}

type Derived struct {
	Base
}

func (d *Derived) ShowB() {
	fmt.Println("Derived showB")
}

func main() {
	d := Derived{}
	d.ShowA()
}

上述代碼執行結果不會輸出「Derived showB」,由於Go中沒有繼承的概念,只有組合,上面的Derived包含了Base,自動的含有了Base的方法,由於其不是繼承,因此不會根據具體傳入的對象而執行對應的方法。import

 

下面的的代碼又說明了type name和type struct的區別:變量

package main

import (
	"fmt"
)

type Mutex struct {
	// nothing
}

func (m *Mutex) Lock() {
	fmt.Println("mutex lock")
}

func (m *Mutex) Unlock() {
	fmt.Println("mutex unlock")
}

type newMutex Mutex

type structMutex struct {
	Mutex
}

func main() {
	m1 := Mutex{}
	m1.Lock()

	// n1 := newMutex{}   
	// n1.Lock()      沒有Lock()方法

	x1 := structMutex{}
	x1.Lock()

}

上面的代碼中n1不能執行Lock( )函數,由於Golang不支持隱式類型轉換,雖然newMutex就是Mutex,但語法上它們是兩種類型,所以newMutex不能執行Lock( )方法。

相關文章
相關標籤/搜索