【Go語言入門系列】(八)Go語言是否是面嚮對象語言?

【Go語言入門系列】前面的文章:程序員

1. Go是面向對象的語言嗎?

【Go語言入門系列】(七)如何使用Go的方法?這一文中已經介紹了方法的概念,但這個方法實際上並非面向對象中的方法。方法其實是用戶給其定義的類型的增長的新行爲,實際上也是個函數。算法

關於這個問題,官方文檔中有回答:編程

Yes and no. Although Go has types and methods and allows an object-oriented style of programming, there is no type hierarchy. The concept of 「interface」 in Go provides a different approach that we believe is easy to use and in some ways more general. There are also ways to embed types in other types to provide something analogous—but not identical—to subclassing. Moreover, methods in Go are more general than in C++ or Java: they can be defined for any sort of data, even built-in types such as plain, 「unboxed」 integers. They are not restricted to structs (classes).數據結構

Also, the lack of a type hierarchy makes 「objects」 in Go feel much more lightweight than in languages such as C++ or Java.app

既是也不是。儘管Go擁有類型和方法,也容許面向對象風格的編程,但它沒有類型層級。 在Go中「接口」的概念提供了不一樣的方法,咱們相信它易於使用且在某些方面更通用。 也有一些在其它類型中嵌入類型的方法,來提供相似(而非徹底相同)的東西進行子類化。 此外,Go中的方法比C++或Java中的更通用:它們可被定義爲任何種類的數據。 甚至是像普通的「未裝箱」整數這樣的內建類型。它們並不受結構(類)的限制。數據結構和算法

此外,類型層級的缺失也使Go中的「對象」感受起來比C++或Java的更輕量級ide

有了這個回答,下面介紹的「繼承」和「重寫」的概念並非嚴格的面向對象中的繼承和重寫的概念。這裏只借用這兩個名詞來表示Go的兩種特性。函數

2.「繼承」

在面向對象中,繼承是子類和父類之間的關係,子類會繼承父類的公有成員變量和成員方法。學習

前面提到過,Go容許面向對象風格的編程。那Go如何「繼承」呢?ui

2.1.「繼承」字段

【Go語言入門系列】(五)指針和結構體的使用這一文中,介紹了匿名字段(也叫嵌入字段):

package main

import "fmt"

type people struct {
	name string
	age int
}

type student struct {
	people
	school string
}

func (s student) say() {
	fmt.Printf("我是%s,今年%d歲了,在%s上學。", s.name, s.age, s.school)
}

func main() {
	stu := student{people{"行小觀", 1}, "陽光小學"}
	stu.say()
}

運行:

我是行小觀,今年1歲了,在陽光小學上學

結構體student中有匿名字段people,因此student就有了peoplenameage字段。當匿名字段是一個結構體時,那麼該結構體的所有字段都會被引入當前的結構體中。這是否是很像面向對象中的繼承?子類繼承父類的公有成員變量。

考慮下面一個問題,若是studentpeople中都有name字段,那麼訪問時,Go語言是如何處理的?

package main

import "fmt"

type people struct {
	name string //人名
	age int
}

type student struct {
	people
	name string //學生名
	school string
}

func main() {
	stu := student{people{"李二狗", 1}, "李向前", "陽光學校"}
	fmt.Println(stu.name) //李向前
	fmt.Println(stu.people.name) //李二狗
}

此時就出現了字段衝突,Go會先訪問外層的字段。好比,stu.name李向前(外層),stu.people.name李二狗(內層)。

2.2.「繼承」方法

咱們經過接收者把函數綁定到結構體類型上,這樣的函數稱爲方法,方法就在概念上屬於了接收者對應的結構體。

上面經過結構體中匿名字段實現了「繼承」字段的效果,對於方法來講,一樣能夠。下面是一個實例:

package main

import "fmt"

type people struct {
	name string
	age int
}

type student struct {
	people
	school string
}

type programmer struct {
	people
	language string
}

func (p people) say() {
	fmt.Printf("我是%s,今年%d歲了,和我一塊兒學習Go語言吧!\n", p.name, p.age)
}

func main() {
	stu := student{people{"行小觀", 1}, "陽光小學"}
	stu.say()
	prom := programmer{people{"張三", 1}, "藍天建築有限公司"}
	prom.say()
}

運行:

我是行小觀,今年1歲了,和我一塊兒學習Go語言吧!
我是張三,今年1歲了,和我一塊兒學習Go語言吧!

say()方法的接收者是people類型,而結構體studentprogrammer中都有匿名字段people,因此stuprom都能調用say()方法。這是否是很像面嚮對象語言中子類繼承父類的公有方法?

3. 「重寫」

3.1. 「重寫」字段

前面已經介紹了若是結構體和做爲其字段的結構體的字段衝突瞭如何處理。有了這個特性,咱們就能夠「重寫」字段。

package main

import "fmt"

type people struct {
	name string //乳名
	age int
}

type student struct {
	people
	name string //大名
	school string
}

func (s student) say() {
	fmt.Printf("我是%s,今年%d歲了,和我一塊兒學習Go語言吧!\n", s.name, s.age)
}

func main() {
	stu := student{people{"李二狗", 1}, "李向前","陽光小學"}
	stu.say()
}

運行:

我是李向前,今年1歲了,和我一塊兒學習Go語言吧!

李二狗是乳名,李向前纔是大名。自我介紹時說的是大名李向前。若是須要乳名,則使用stu.people.name

3.2.「重寫」方法

下面是一個實例:

package main

import "fmt"

type people struct {
	name string
	age int
}

type student struct {
	people
	school string
}

type programmer struct {
	people
	language string
}

func (p people) say() { //people的say方法
	fmt.Printf("我是%s,今年%d歲了,和我一塊兒學習Go語言吧!\n", p.name, p.age)
}

func (s student) say() { //student重寫people的say方法
	fmt.Printf("我是%s,是個學生,今年%d歲了,我在%s上學!\n", s.name, s.age, s.school)
}

func (p programmer) say() { //programmer重寫people的say方法
	fmt.Printf("我是%s,是個程序員,今年%d歲了,我使用%s語言!\n", p.name, p.age, p.language)
}

func main() {
	stu := student{people{"李向前", 1}, "陽光小學"}
	stu.say()
	prmger := programmer{people{"張三", 1}, "Go"}
	prmger.say()
}

運行:

我是李向前,是個學生,今年1歲了,我在陽光小學上學!
我是張三,是個程序員,今年1歲了,我使用Go語言!

studentprogrammer「繼承」了peoplesay()方法,可是不合適,因而各自「重寫」了say()方法。

看到這裏,你就理解了官方文檔中的那兩句話是什麼意思了。

「儘管Go擁有類型和方法,也容許面向對象風格的編程,但它沒有類型層級」

「類型層級的缺失也使Go中的「對象」感受起來比C++或Java的更輕量級」

做者簡介

我是行小觀,我會在公衆號『行人觀學』中持續更新Java、Go、數據結構和算法、計算機基礎等相關文章。


本文章已收錄進系列文章「Go語言入門系列」,本系列從Go語言基礎開始介紹,適合從零開始的初學者。


歡迎關注,咱們一塊兒踏上編程的行程。

若有錯誤,還請指正。

相關文章
相關標籤/搜索