(1)面向對象

類型系統

類型系統是指一個語言的類型體系結構。一個典型的類型系統通常包含以下內容:

  • 基礎類型:byte int bool ...
  • 復合類型:數組 結構體 指針 ...
  • 可以指向任意對象的類型(Any類型)
  • 值語義和引用語義
  • 面向對象的特征 如成員方法
  • 接口

類型系統描述的是這些內容在一個語言中如何被關聯。

以java舉例,在Java中存在兩套完全獨立的類型系統:一套是值類型系統,主要是基本數據類型(int byte char 等 ),這些類型是值語義的。另一套則是以Object為根的對象類型,這些類型可以定義成員變量和成員方法。java中的Any類型就是Object,值類型想要被Object引用需要裝箱(int->Integer)。

相比之下Go語言的大多數類型都是值語義,并且都可以包含對應的操作方法。在需要的時候可以給任何類型添加新方法。而在實現某個接口時,無需從該接口繼續(Go不支持繼承),只要實現該接口要求的所有方法即可。GO語言的Any類型就是空接口interface(),可以引用任何類型。

為類型添加方法

例1:

package main

import "fmt"

type Integer int

func (a Integer) Less(b Integer) bool  {
    return a<b
}

func main()  {
    var a Integer =1
    if a.Less(2){
        fmt.Println(a,"less 2")
    }
}


運行結果:
1 less 2

Process finished with exit code 0

例1 定義了一個新類型Integer,我們為其新增了一個Less方法。

例2:

package main
import "fmt"
type Integer int

func (a *Integer) Add(b Integer) {
    *a += b
}

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

Go語言中的面向對象最為直觀,如果要求對象必須以指針傳遞,這有時會是個額外成本,有時對象很小,用指針傳遞并不劃算。
只有在你需要修改對象的時候,才必須使用指針,比如例2
如果你寫成這樣

func (a *nteger) Add(b Integer) {
    a += b
}

那么你得打的值仍然會是1,而不是3。因為go語言類型都是屬于值傳遞,要想修改變量的值,只能傳遞指針。

值語義和引用語義

值語義和引用語義的差別在于賦值
b = a
b.Modify()
如果b的修改不會影響a,屬于值類型,如果影響屬于引用類型。

Go語言中大多數屬于值類型,包括:

  • 基本類型 int bool 等
  • 復合類型 array 結構體struct 指針

Go語言中有4個類型比較特別,看起來像引用類型

  • 數組切片:指向數組的一個區間
  • map:極其常見的數據類型
  • channel:執行體間的通信設施
  • 接口:對一組滿足某個契約的類型的抽象
結構體

Go 語言的結構體(struct)和其他語言的類(class)有同等地位,但Go放棄了包括繼承在內的大量的面向對象的特性,只保留了組合這個最基礎的特性。

定義一個矩形類型,再定義Area成員方法來計算面積

type Rect struct {
    x, y float64
    width, hight float64
}

func (rect *Rect)Area() float64 {
    return rect.hight*rect.width
}
初始化

定義好了Rect,可以有以下幾種方式初始化:

rect1 := new(Rect)
rect2 :=&Rect{0,0,100,100}
rect3 :=&Rect{width:100,hight:100}
rect4 :=&Rect{}

Go語言沒有構函數,使用一個全局的創建函數new來創建

匿名組合

確切的說,Go語言也提供了繼承,但是采用了組合的文法,我們稱之為匿名組合

type Base struct {
    Name string
}

func (base *Base)Foo()  {
}
func (base *Base)Bar()  {
}

type Foo struct {
    Base
}

func (foo *Foo) Bar() {
    foo.Base.Bar()
}

以上代碼定義了一個Base類,實現了Foo()和Bar(),然后定義了一個Foo類,該類從Base類“繼承”并改寫了Bar()

可見性

Go語言對關鍵字的增加非常的吝嗇,其中沒有private、protected、public這樣的關鍵字,要使某個符號對其他包可見,需要定義此符號定義為大寫字母

接口

接口在Go語言有著至高重要的地位,接口是Go語言整個類型系統的基石,讓Go語言在基礎編程哲學的探索上達到前所未有的高度。

非侵入式接口

在Go語言中,一個類只需要實現了接口所有的函數,我們就說這個類實現了該接口,甚至可以不知道接口的存在,例如以下File類并沒有繼承IFile IRead IWrite,但是實現了這些接口,所以就可以進行賦值。

type IFile interface{
  Read (buf []byte) (n int,err error)
  Write(buf []byte)(n int,err error)
  Seek(off int64,whene int)(pos int64,err error)
  Close(err error)
}

type IRead interface{
 Read (buf []byte) (n int,err error)
}

type IWrite interface{
    Write (buf []byte) (n int,err error)
}

type File struct {

}
func (f *File) Read (buf []byte) (n int,err error){}
func (f *File) Write(buf []byte)(n int,err error){}
func (f *File) Seek(off int64,whene int)(pos int64,err error){}
func (f *File) Close(err error){}

//賦值
var file1 IFile = new(File)
var file2 IRead = new(File)
var file3 IWrite = new(File)
接口賦值

接口賦值在Go語言中有兩種情況:
將對象實例賦值給接口
將一個接口賦值給另一個接口

將某種類型的對象賦值給接口

type Integer int
func (a Integer) Less (b Integer)bool{
    return a<b
}

func (a *Integer) Add (b Integer)bool{
    *a +=b
}

//定義接口LessAdder
type LessAdder interface{
    Less (b Integer)bool
    Add (b Integer)
}

//將對象賦值給接口
var a Integer = 1
var b LessAdder =&a  (1)
var b LessAdder =a   (2)

//其中(1)是正確的賦值是(1)
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容