Go是面向對象的嗎?

有時,我讀到一篇文章“ Go是面向對象的”。有時,另一篇文章聲稱Go不能完成面向對象的編程,只是因為它沒有類。

所以我寫了這篇文章來澄清這個話題。 Go是否面向對象?

如果您習慣用一種特定的語言來思考,這取決於您使用的是哪種語言,那麼您可能對該主題有不同的看法。例如,如果您來自C,那麼顯然Go具有更多的面向對象編程功能。來自Java的Go代碼看起來不太面向對象。

在這種情況下,您需要做的就是停止以“其他語言”的方式思考,而首先以Go的思維方式進行思考。

這是我的答案:是的,Go是面向對象的,並且在令人耳目一新一種理智的道路。

前往常見問題說:

Go是一種面向對象的語言嗎?

是的,沒有。儘管Go具有類型和方法,並允許使用面向對象的編程風格,但沒有類型層次結構。 Go中的“接口”概念提供了一種不同的方法,我們認為該方法易於使用,並且在某些方面更通用。還有一些方法可以將類型嵌入其他類型,以提供與子類類似(但不完全相同)的東西。而且,Go中的方法比C ++或Java中的方法更通用:可以為任何類型的數據定義它們,甚至可以將內置類型(例如普通的“未裝箱”整數)定義為它們。它們不限於結構(類)。

而且,缺乏類型層次結構使得Go中的“對象”比C ++或Java等語言更輕量。

摘櫻桃的概念

Go從過程式編程,函數式編程和麵向對象的編程中選擇了一些概念,並將它們組合在一起,並省略了其他概念以創建自己獨特的慣用編程風格。

沒有課程,請輸入結構

按照傳統的概念,Go中沒有類,但是Go具有結構類型,它們比它們的功能強大得多。C對應。結構類型及其相關方法達到了傳統類的相同目標,在傳統類中,結構僅保留狀態,而不包含行為,並且這些方法通過允許更改狀態來提供行為。

封裝形式

Go的最佳功能之一:大寫的字段,方法和功能是公開的。所有其他字段對於程序包而言是本地的,不會導出。一眼就能知道是公共的還是私人的。沒有啦受保護的因為沒有繼承。

沒有繼承

沒有繼承的概念。從Go常見問題解答中:

至少以最著名的語言進行的面向對象編程涉及對類型之間的關係的過多討論,而這些關係通常可以自動派生。 Go採用了不同的方法。

組成重於繼承

眾所周知的原理,在《四人幫》一書中也提到過,在Go代碼中有很多發現。

在聲明結構時,我們可以添加一個未命名(匿名)字段,這將導致其字段及其方法在結構上公開。這就是所謂的結構嵌入

package main

import ( “fmt” )

type Dog struct { Animal } type Animal struct { Age int }

func (a Animal) Move() { fmt.Println(“Animal moved”) } func (a Animal) SayAge() { fmt.Printf(“Animal age: %d\n”, a.Age) } func main() { d := Dog{} d.Age = 3 d.Move() d.SayAge() }

介面

忘記Java和PHP風格的接口。 Go接口有很大的不同,一個關鍵概念是接口要滿足隱含地

從Go常見問題解答中:

在Go中,類型無需自動聲明兩種類型相關聯,而可以自動滿足指定其方法子集的任何接口。

接口通常很小,最多只能是一種方法。您不會在慣用的Go中看到很長的方法列表。

界面優雅地提供多態性:通過接受接口,您聲明接受任何滿足該接口的對象。

方法

類型有方法。它們是在類型定義之外定義的,其語法可能會調用JavaScript原型方法定義:

function Person(first, last) {
    this.firstName = first;
    this.lastName = last;
}
Person.prototype.name = function() {
    return this.firstName + " " + this.lastName;
};
p = new Person("Flavio", "Copes")
p.name() // Flavio Copes

在Go中,相同的代碼編寫為:

package main

import ( “fmt” ) type Person struct { firstName string lastName string } func (p Person) name() string { return p.firstName + " " + p.lastName } func main() { p := Person{“Flavio”, “Copes”} fmt.Println(p.name()) }

將方法附加到類型

方法可以附加到任何類型,甚至是基本數據類型。由於方法只能附加在定義了類型的同一包中,因此我們不能“豐富”內置的基本類型,但可以使用基礎類型作為基礎表示形式來豐富我們創建的任何命名類型:

package main

import ( “fmt” )

type Amount int

func (a Amount) Add(add Amount) { a += add }

func main() { var a Amount a = 1 a.Add(2) fmt.Println(a) }

功能

考慮一下像Java這樣的傳統的面向對象的編程語言。您用靜態方法定義了幾次“ Utils”類?

這是為了解決所有事物都是對象,並且函數定義必須在類內部的想法。 Go不會發生這種事情,因為Go具有功能。在現實世界中,並非所有事物都必須是對像或方法。 “類”和“對象”非常有用,但不能用於所有事物。

在Go中,並非所有事物都是對象(從技術上講,不是所有東西都是對象,但是有些人稱類型值和變量為“對象”),方法是與類型關聯的函數,但是Go也允許函數駐留在對像外部,就像C一樣。功能。

因此,儘管Go允許使用方法,但它也允許使用函數,並且一流的功能(函數可以存儲為struct字段,可以作為參數傳遞給其他函數,可以從函數或方法的返回值中返回)。

減少腫脹

總體而言,面向對象編程的Go實現令人難以置信靈活的直接的。拋開類和繼承,您會看到很少的樣板,並且不必推理很難更改的類的完美層次結構,而是可以根據需要自由地組合和分解類型。


更多教程: