Go type關(guān)鍵字(類型定義與類型別名的使用差異)用法實(shí)例探究
1. 類型別名定義
定義類型別名的寫法為:
type TypeAlias = Type
類型別名規(guī)定:TypeAlias 只是 Type 的別名,本質(zhì)上 TypeAlias 與 Type 是同一個(gè)類型,就像一個(gè)孩子小時(shí)候有小名、乳名,上學(xué)后用學(xué)名,英語老師又會給他起英文名,但這些名字都指的是他本人。
2. 類型定義
類型定義語法如下:
type newType Type
其中 newType 是一種新的類型, newType 本身依然具備 Type 類型的特性。
類型聲明語句一般出現(xiàn)在包一級,因此如果新創(chuàng)建的類型名字的首字符大寫,則在包外部也可以使用。
一個(gè)類型聲明語句創(chuàng)建了一個(gè)新的類型名稱,和現(xiàn)有類型具有相同的底層結(jié)構(gòu)。新命名的類型提供了一個(gè)方法,用來分隔不同概念的類型,這樣即使它們底層類型相同也是不兼容的。
為了說明類型聲明,我們將不同溫度單位分別定義為不同的類型:
package main
type Celsius float64 // 攝氏溫度
type Fahrenheit float64 // 華氏溫度
const (
AbsoluteZeroC Celsius = -273.15 // 絕對零度
FreezingC Celsius = 0 // 結(jié)冰點(diǎn)溫度
BoilingC Celsius = 100 // 沸水溫度
)
func CToF(c Celsius) Fahrenheit {
return Fahrenheit(c*9/5 + 32)
}
func FToC(f Fahrenheit) Celsius {
return Celsius((f - 32) * 5 / 9)
}
我們在這個(gè)包聲明了兩種類型:Celsius 和 Fahrenheit 分別對應(yīng)不同的溫度單位。它們雖然有著相同的底層類型 float64 ,但是它們是不同的數(shù)據(jù)類型,因此它們不可以被相互比較或混在一個(gè)表達(dá)式運(yùn)算。
刻意區(qū)分類型,可以避免一些像無意中使用不同單位的溫度混合計(jì)算導(dǎo)致的錯(cuò)誤;因此需要一個(gè)類似 Celsius(t) 或 Fahrenheit(t) 形式的顯式轉(zhuǎn)型操作才能將 float64 轉(zhuǎn)為對應(yīng)的類型。
只有當(dāng)兩個(gè)類型的底層基礎(chǔ)類型相同時(shí),才允許這種轉(zhuǎn)型操作,或者是兩者都是指向相同底層結(jié)構(gòu)的指針類型,這些轉(zhuǎn)換只改變類型而不會影響值本身。如果 x 是可以賦值給 T 類型的值,那么 x 必然也可以被轉(zhuǎn)為 T 類型,但是一般沒有這個(gè)必要。
底層數(shù)據(jù)類型決定了內(nèi)部結(jié)構(gòu)和表達(dá)方式,也決定是否可以像底層類型一樣對內(nèi)置運(yùn)算符的支持。這意味著, Celsius 和 Fahrenheit 類型的算術(shù)運(yùn)算行為和底層的 float64 類型是一樣的,正如我們所期望的那樣。
fmt.Printf("%g\n", BoilingC-FreezingC) // "100" °C</code><code>boilingF := CToF(BoilingC)</code><code>fmt.Printf("%g\n", boilingF-CToF(FreezingC)) // "180" °F
fmt.Printf("%g\n", boilingF-FreezingC) // compile error: type mismatch
比較運(yùn)算符==和<也可以用來比較一個(gè)命名類型的變量和另一個(gè)有相同類型的變量,或有著相同底層類型的未命名類型的值之間做比較。但是如果兩個(gè)值有著不同的類型,則不能直接進(jìn)行比較:
var c Celsius var f Fahrenheit fmt.Println(c == 0) // "true" fmt.Println(f >= 0) // "true" fmt.Println(c == f) // compile error: type mismatch fmt.Println(c == Celsius(f)) // "true"!
注意最后那個(gè)語句。盡管看起來像函數(shù)調(diào)用,但是 Celsius(f) 是類型轉(zhuǎn)換操作,它并不會改變值,僅僅是改變值的類型而已。測試為真的原因是因?yàn)?nbsp;c 和 g 都是零值。
命名類型還可以為該類型的值定義新的行為。這些行為表示為一組關(guān)聯(lián)到該類型的函數(shù)集合,我們稱為類型的方法集。
下面的聲明語句, Celsius 類型的參數(shù) c 出現(xiàn)在了函數(shù)名的前面,表示聲明的是 Celsius 類型的一個(gè)名叫 String 的方法,該方法返回該類型對象 c 帶著 °C 溫度單位的字符串:
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
許多類型都會定義一個(gè) String 方法,因?yàn)楫?dāng)使用 fmt 包的打印方法時(shí),將會優(yōu)先使用該類型對應(yīng)的 String 方法返回的結(jié)果打印。
c := FToC(212.0)
fmt.Println(c.String()) // "100°C"
fmt.Printf("%v\n", c) // "100°C"; no need to call String explicitly
fmt.Printf("%s\n", c) // "100°C"
fmt.Println(c) // "100°C"
fmt.Printf("%g\n", c) // "100"; does not call String
fmt.Println(float64(c)) // "100"; does not call String
3. 類型別名與類型定義差異
類型別名與類型定義表面上看只有一個(gè)等號的差異,那么它們之間實(shí)際的區(qū)別有哪些呢?下面通過一段代碼來理解。
package main
import (
"fmt"
)
// 將NewInt定義為int類型
// 通過 type 關(guān)鍵字的定義,NewInt 會形成一種新的類型,NewInt 本身依然具備 int 類型的特性。
type NewInt int
// 將int取一個(gè)別名叫IntAlias, 將 IntAlias 設(shè)置為 int 的一個(gè)別名,使 IntAlias 與 int 等效。
type IntAlias = int
func main() {
// 將a聲明為NewInt類型
var a NewInt
// 查看a的類型名
fmt.Printf("a type: %T\n", a) // a type: main.NewInt
// 將 b 聲明為IntAlias類型
var b IntAlias
// 查看b的類型名
fmt.Printf("b type: %T\n", b) // b type: int
}結(jié)果顯示 a 的類型是 main.NewInt ,表示 main 包下定義的 NewInt 類型,b 類型是 int , IntAlias 類型只會在代碼中存在,編譯完成時(shí),不會有 IntAlias 類型。
4. 非本地類型不能定義方法
能夠隨意地為各種類型起名字,是否意味著可以在自己包里為這些類型任意添加方法呢?參見下面的代碼演示:
package main
import (
"time"
)
// 定義time.Duration的別名為MyDuration
type MyDuration = time.Duration
// 為 MyDuration 添加一個(gè)方法
func (m MyDuration) EasySet(a string) {
}
func main() {
}錯(cuò)誤信息:
./hello.go:11:6: cannot define new methods on non-local type time.Duration
編譯器提示:不能在一個(gè)非本地的類型 time.Duration 上定義新方法,非本地類型指的就是 time.Duration 不是在 main 包中定義的,而是在 time 包中定義的,與 main 包不在同一個(gè)包中,因此不能為不在一個(gè)包中的類型定義方法。修改方案為將第 8 行類型別名修改為類型定義,如下:
type MyDuration time.Duration
以上就是Go type關(guān)鍵字(類型定義與類型別名的使用差異)用法實(shí)例探究的詳細(xì)內(nèi)容,更多關(guān)于Go type關(guān)鍵字的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Golang的os標(biāo)準(zhǔn)庫中常用函數(shù)的整理介紹
這篇文章主要介紹了Go語言的os標(biāo)準(zhǔn)庫中常用函數(shù),主要用來實(shí)現(xiàn)與操作系統(tǒng)的交互功能,需要的朋友可以參考下2015-10-10
Go語言的隊(duì)列和堆棧實(shí)現(xiàn)方法
這篇文章主要介紹了Go語言的隊(duì)列和堆棧實(shí)現(xiàn)方法,涉及container/list包的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02

