學習Go語言差不多快兩個月了,感覺這個過程還是蠻快樂的,翻翻英文資料,寫寫小程式,總是覺得有好多東西都搞不明白,一步步走下來,卻發現,這些迷惑好像也是不可或缺的。慢慢思考,最終也找到瞭解決方法,可能不是最好的,但是我會隨著認識的不斷深入,繼續修改。
因為java的東西在我的知識體系中是根深蒂固的,儘管我現在很討厭java體系中的一些東西。對於曾經搞過java的人來說,去學習任何一門新的語言,首先會問,是否是物件導向的語言。剛接觸GO的幾天,曾經帶我的師傅問我go是不是一門物件導向的語言,我閃爍其詞,因為我還沒有搞清楚到底是不是。物件導向思想是一種很好得方法(到目前來說我認為還是這樣)。Go嚴格來說不是一門物件導向的語言,但是,其中的很多方式還是借鑒了物件導向的一些思想,儘管Go更接近C,但是從物件導向這塊,從事java的開發人員還是不陌生的。
物件導向的三大特點:封裝、繼承、多態。
封裝:就我自己的理解而言,封裝就是將某些特徵組裝到一起,其他的對象或類可以使用這個整體,卻不一定能夠知道其實現細節。這又涉及到是否可見的問題。在java中,有privat,public,protected關鍵字來決定訪問的許可權。而在go中,採用了一種算是規定的方法:使用大小寫來確定,大寫是包外可見的,小寫struct或函數只能在包內使用。(go的關鍵字是及其少,簡直可以說是吝嗇,這也是其簡潔的一個原因吧)。Java中,每個class都有其屬性和方法,在go中,沒有class的概念,與C語言一樣,有struct的概念。與C語言不同的是,可以定義只用於這個struct的方法。看個例子會清晰很多。
// lxy project lxy.gopackage lxyimport "strconv"type Student struct { Name string Age int}func (s *Student) SetName(name string) { s.Name = name}func (s *Student) GetName() string { return s.Name}func (s *Student) SetAge(age int) { s.Age = age}func (s *Student) GetAge() int { return s.Age}func (s *Student) String() string { return "name is " + s.Name + ",age is " + strconv.Itoa(s.Age)}
先說一下在go中函數定義的格式吧。
func (ptype)
funcName(a type)(btype){}
紅色的func是定義函數的關鍵字,是不可變的,綠色部分是可選的,當然,如果有這部分,那就不是個函數了,而是一個方法。這種實現方式相當於是定義了,這個方法只用於這個type的執行個體。紫色部分代表的是函數的傳回值。這個有點奇怪啊。向我們熟悉的語言,不管是java還是C,都會把傳回值放在函數名前邊,go卻把它放到了最後。還有,go中的函數可以有0-n個傳回值,並且可以指定傳回值的名字。
結構體Student封裝了兩個方法,Name和Age,這兩個熟悉包括結構體都是包外可以使用的。然後又給這個結構體定義了幾個方法。看一下在主函數中的調用。
package mainimport ( "fmt" "lxy")func main() { ss := new(lxy.Student) ss.SetName("lxy") ss.SetAge(20) fmt.Println(ss.String())}
在go中,要想調用另外一個package中的內容,需要首先import.在go中,所有的都會在一個特定的包中定義或者使用。使用方式為包名.(方法或者全域變數)
繼承:在go中,沒有明確說明繼承的關鍵字,我使用的,我不確定是否是真正意義上的繼承,姑且稱之為類比繼承吧。還是看例子。
package mainimport ( "fmt" "lxy")type director struct { lxy.Student Name string}func (di *director) GetName() string { fmt.Println("get director name") return di.Name}func main() { ss := new(lxy.Student) ss.SetName("lxy") ss.SetAge(20) dd := new(director) dd.Name = "director" dd.Student = *ss fmt.Println(dd.GetName())fmt.Println(dd.Student.GetName())fmt.Println(dd.GetAge())}
還是剛才的代碼,我只是在主函數所在的包中又增加了一個結構體,它包含了Student,而且是匿名包含的,這實際上就是一個繼承。Director的執行個體可以直接調用Student中的所有方法,如最後一條語句。對於一些衝突的處理包括:像本例中,director中包含了GetName方法和Name屬性,與Student中是完全一樣的,因為這個沒有出現在同一個level(何為同一個lever呢?本例中,director中的Name和lxy.Student就是同一個level),所以調用的是level最高的。若是處於同一個level的包含相同的變數名或者方法名,那就必須要明確指明了。比如
type A struct{
a int
b string
}
type B struct{
a int
c string
}
type C struct{
A
B
}
此時調用var cc C;cc.a 就錯了,因為編譯器不清楚到底是A還是B的a屬性,這個需要指明是cc.A.a還是cc.B.a
多態:這個概念該怎麼說呢,介面的多種不同實現方式。比如一個介面方法:叫。如果貓實現了這個介面,則結果會是“喵喵”;狗實現了這個方法,結果會是“汪汪”…..go中也有介面,只是其實現方式比較奇怪一些,閑話少說,還是拿例子說事:
// lxy project lxy.gopackage lxyimport "strconv"type IPeople interface { SetName(string) GetName() string}type Student struct { Name string Age int}type Teacher struct { Name string Course string}func (s *Student) SetName(name string) { s.Name = name}func (t *Teacher) SetName(name string) { t.Name = name}func (s *Student) GetName() string { return s.Name}func (t *Teacher) GetName() string { return t.Name}func (s *Student) SetAge(age int) { s.Age = age}func (s *Student) GetAge() int { return s.Age}func (s *Student) String() string { return "name is " + s.Name + ",age is " + strconv.Itoa(s.Age)}func (t *Teacher) SetCourse(course string) { t.Course = course}func (t *Teacher) GetCourse() string { return t.Course}
代碼中紅色部分定義了一個介面IPeople,其包括兩個方法。上述代碼,我們可以得出一個結論,Teacher和Student都實現了介面IPeople.還沒看出來是吧。因為Teacher和Student都實現了介面IPeople的兩個方法。在go中,不需要顯示聲明某個struct是否聲明了介面,只要其包括介面中的方法,go編譯器就認為這個struct實現了這個介面了。即使介面與這個struct不在同一個包中,也會認為是實現了這個介面。看下主函數中:
package mainimport ( "fmt" "lxy")type director struct { lxy.Student Name string}func (di *director) GetName() string { fmt.Println("get director name") return di.Name}func (di *director) SetName(name string) { di.Name = name}func main() { ss := new(lxy.Student) ss.SetName("lxy") ss.SetAge(20) dd := new(director) dd.Name = "director" dd.Student = *ss var ii lxy.IPeople ii = dd ii.SetName("test") fmt.Println(ii.GetName())}
一個struct可以實現多個介面,一個介面也可以被多個struct實現,這些與大家熟知的物件導向語言相同。介面在go語言中是很重要的一種結構,其意義遠比在java中深遠。具體的大家可以參考下go的學習資料。
差不多吧,我想到且知道的就是這些,雖然不是嚴格意義上的物件導向,但是最起碼做到了神似。