咱們知道Go中沒有繼承,接口的用法也與Java中的用法截然不同,不少適合,咱們須要使用OO的思想來組織咱們達到項目,可是將Java的oo思想在Go中會比較痛苦,Go中的方法和麪向對象的相似,可是定義上也是不少初學者很差理解的,好比方法的定義居然在結構體外部,組裝起來看起來也很隨意,其實Go只是有面向對象特性,其實不算是面嚮對象語言。html
Go支持一些面向對象編程特性,方法是這些所支持的特性之一。 本篇文章將介紹在Go中和方法相關的各類概念編程
在Go中,咱們能夠爲類型T
和*T
顯式地聲明一個方法,其中類型T
必須知足四個條件:函數
T
必須是一個定義類型;T
必須和此方法聲明定義在同一個代碼包中;T
不能是一個指針類型;T
不能是一個接口類型。類型T
和*T
稱爲它們各自的方法的屬主類型(receiver type)。 類型T
被稱做爲類型T
和*T
聲明的全部方法的屬主基類型(receiver base type)大數據
若是咱們爲某個類型聲明瞭一個方法,之後咱們能夠說此類型擁有此方法,一個方法聲明和一個函數聲明很類似,可是比函數聲明多了一個額外的參數聲明部分。 此額外的參數聲明部分只能含有一個類型爲此方法的屬主類型的參數,此參數稱爲此方法聲明的屬主參數(receiver parameter)。 此屬主參數聲明必須包裹在一對小括號()之中。 此屬主參數聲明部分必須處於func關鍵字和方法名之間人工智能
下面是一個方法聲明的例子:spa
// Age和int是兩個不一樣的類型。咱們不能爲int和*int // 類型聲明方法,可是能夠爲Age和*Age類型聲明方法。 type Age int func (age Age) LargerThan(a Age) bool { return age > a } func (age *Age) Increase() { *age++ } // 爲自定義的函數類型FilterFunc聲明方法。 type FilterFunc func(in int) bool func (ff FilterFunc) Filte(in int) bool { return ff(in) } // 爲自定義的映射類型StringSet聲明方法。 type StringSet map[string]struct{} func (ss StringSet) Has(key string) bool { _, present := ss[key] return present } func (ss StringSet) Add(key string) { ss[key] = struct{}{} } func (ss StringSet) Remove(key string) { delete(ss, key) } // 爲自定義的結構體類型Book和它的指針類型*Book聲明方法。 type Book struct { pages int } func (b Book) Pages() int { return b.pages } func (b *Book) SetPages(pages int) { b.pages = pages }
對每一個方法聲明,編譯器將自動隱式聲明一個相對應的函數。 好比對於上一節的例子中爲類型Book
和*Book
聲明的兩個方法,編譯器將自動聲明下面的兩個函數:prototype
func Book.Pages(b Book) int { return b.pages // 此函數體和Book類型的Pages方法體同樣 } func (*Book).SetPages(b *Book, pages int) { b.pages = pages // 此函數體和*Book類型的SetPages方法體同樣 }
在上面的兩個隱式函數聲明中,它們各自對應的方法聲明的屬主參數聲明被插入到了普通參數聲明的第一位。 它們的函數體和各自對應的顯式方法的方法體是同樣的。指針
兩個隱式函數名Book.Pages
和(*Book).SetPages
都是aType.MethodName
這種形式的。 咱們不能顯式聲明名稱爲這種形式的函數,由於這種形式不屬於合法標識符。這樣的函數只能由編譯器隱式聲明。 可是咱們能夠在代碼中調用這些隱式聲明的函數code
一個方法原型能夠看做是一個不帶func關鍵字的函數原型。 咱們能夠把每一個方法聲明看做是由一個func關鍵字、一個屬主參數聲明部分、一個方法原型和一個方法體組成htm
方法事實上是特殊的函數。方法也常被稱爲成員函數。 當一個類型擁有一個方法,則此類型的每一個值將擁有一個不可修改的函數類型的成員(相似於結構體的字段)。 此成員的名稱爲此方法名,它的類型和此方法的聲明中不包括屬主部分的函數聲明的類型一致。 一個值的成員函數也能夠稱爲此值的方法。
一個方法調用實際上是調用了一個值的成員函數。假設一個值v
有一個名爲m
的方法,則此方法能夠用選擇器語法形式v.m
來表示。
下面這個例子展現瞭如何調用爲Book
和*Book
類型聲明的方法:
package main import "fmt" type Book struct { pages int } func (b Book) Pages() int { return b.pages } func (b *Book) SetPages(pages int) { b.pages = pages } func main() { var book Book fmt.Printf("%T \n", book.Pages) // func() int fmt.Printf("%T \n", (&book).SetPages) // func(int) // &book值有一個隱式方法Pages。 fmt.Printf("%T \n", (&book).Pages) // func() int // 調用這三個方法。 (&book).SetPages(123) book.SetPages(123) // 等價於上一行 fmt.Println(book.Pages()) // 123 fmt.Println((&book).Pages()) // 123 }
和普通參數傳參同樣,屬主參數的傳參也是一個值複製過程。 因此,在方法體內對屬主參數的直接部分的修改將不會反映到方法體外
更多詳細內容能夠查看 https://gfw.go101.org/article/101.html
吳邪,小三爺,混跡於後臺,大數據,人工智能領域的小菜鳥。
更多請關注