文章目錄
面向Java開發人員的GO編程
英文原文在此www.nada.kth.se/~snilsson/go_for_java_programmers
譯文同步至www.waylau.com
http://bbs.gocn.im/thread-86-1-1.html
=======================接上文========================.
Slices(切片)
slice是概念上一個結構包含三個域:一個數組的指標、長度和容量。切片支援[]
操作符來訪問底層數組的元素。內建的len
函數返回的切片長度。內建的的cap
函數返回切片的能力。
給定一個數組,或另一個切片,通過a[i:j]
來建立一個新的切片。這個新建立的切片指向a
,從索引i
開始,並結束索引j
之前。它的長度是j - i
。如果i
被省略,切片從0開始。如果j
被省略,切片在len(a)
結束。新切片跟a
一樣指向相同的數組。即,改變後組成的新的切片的元素在a
都能見到。新切片的容量就是簡單的a
減去i
。數組的容量就是數組的長度。
var s []intvar a [10]ints = a[:] // short for s = a[0:len(a)]
如果你建立一個實值型別為[100]byte
(100個位元組,也許是一個緩衝區的數組),你想不複製它,而將它傳遞給函數,那麼函數的參數宣告類型[]byte
,並傳入數組的切片。切片也可以用make
的函數建立(如下文所述)。
切片組合採用內建的append
函數,Java的ArrayList
提供相同的功能。
s0 := []int{1, 2}s1 := append(s0, 3) // append a single elements2 := append(s1, 4, 5) // append multiple elementss3 := append(s2, s0...) // append a slice
切片文法,也可以使用在字串上。它返回一個新字串,其值是原始的字串的子串
make函數
Map and channel values must be allocated using the built-in function make
. For example, calling map和channel值必須使用內建的函數make
。例如,調用
make(map[string]int)
map[string]int
返回一個新分配的實值型別。相對於new
, make
返回的是實際的對象,而不是一個地址。這是一致的事實,map和channel是參考型別。
對於map,make函數將容量作為一個可選的第二個參數的提示。對於channel,有一個可選的第二個參數來設定channel的緩衝能力,預設為0(無緩衝)。
make
函數也可以用來分配一個切片。在這種情況下,它分配記憶體給基本數組並返回一個引用他的切片。該切片中的元素數是一個必要參數。第二個可選的參數是切片的容量。
m := make([]int, 10, 20) // Same as new([20]int)[:10]
方法和介面方法
方法看起來像一個普通的函數定義,但它有一個receiver(接收者)。receiver是類似Java執行個體方法中的this引用。
type MyType struct { i int }func (p *MyType) Get() int { return p.i}var pm = new(MyType)var n = pm.Get()
這聲明了一個方法Get
與MyType
關聯的。receiver被命名為p
在函數體內。
命名的類型來定義方法。如果您轉換不同類型的值,新的值將有新的類型,而不是那些舊的類型。
你可以定義一個內建類型的方法,用新的命名型別宣告。新的類型和內建的類型是不同的。
type MyInt intfunc (p MyInt) Get() int { return int(p) // The conversion is required.}func f(i int) {}var v MyIntv = v * v // The operators of the underlying type still apply.f(int(v)) // int(v) has no defined methods.f(v) // INVALID
介面
Go介面類似於Java介面,但可被視為一個實現該介面提供任何類型的在Go介面命名的方法。明確的聲明是不必要的。
介面像這樣:
type MyInterface interface { Get() int Set(i int)}
自從 MyType
已經有了Get
方法, 我們可以讓 MyType
滿足介面通過添加
func (p *MyType) Set(i int) { p.i = i}
現在任何只要將MyInterface
當做參數就可以接收類型是*MyType
的變數
func GetAndSet(x MyInterface) {}func f1() { var p MyType GetAndSet(&p)}
在Java術語,給*MyType
定義 Set
和Get
使*MyType
自動實現了MyInterface
介面。這種類型型可滿足多個介面。這是一種形式的鴨子類型。
“當看到一隻鳥走起來像鴨子、遊泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就可以被稱為鴨子。”
James Whitcomb Riley
匿名域
匿名域可以用於實現很像一個Java子類的東西。
type MySubType struct { MyType j int}func (p *MySubType) Get() int { p.j++ return p.MyType.Get()}
MySubType
有效實現的像是MyType
的子類型.
func f2() { var p MySubType GetAndSet(&p)}
Set
方法是繼承自MyType
的,因為關聯了匿名域的方法的變為了封閉類型的方法。在這種情況下,因為
MySubType
有一個匿名與域 MyType
類型,所以為 MyType
e的方法也成為MySubType
的方法。Get
方法被重寫,Set
方法被繼承。
這是與Java中的子類不完全相同。當一個匿名域的方法被調用時,它的 receiver就是這個匿名域,而不是周圍的結構體。換句話說,匿名域上的方法的不會動態調度。當你想要實現相當於Java的動態方法尋找,請使用介面。
func f3() { var v MyInterface v = new(MyType) v.Get() // Call the Get method for *MyType. v = new(MySubType) v.Get() // Call the Get method for *MySubType.}
類型斷言
使用一個類型斷言可以使具有一個介面類型的變數轉換成具有不同的介面類型。這是在運行時動態執行。與Java不同,並不需要任何聲明兩個介面之間的關係。
type Printer interface { Print()}func f4(x MyInterface) { x.(Printer).Print() // type assertion to Printer}
轉換為Printer
完全是動態。只要x
(x中儲存的值的實際類型)的 動態類型 定義了一個Print
方法。
===================未完待續.......==========
===================轉載註明出處=============
2013-1-4