Go語言學習12-類型轉換

類型轉換

1. 概念

類型轉換是把一個類型的值轉換成爲另外一個類型的值。把這個值原來的類型稱爲源類型,而這個值被轉換後的類型稱爲目標類型git

若是 T 是值 x 的目標類型,那麼相應的類型轉換表達式以下:github

T(x) // x能夠是一個表達式,不過這個表達式的結果值只能有一個

若是表明目標類型的字面量始於操做符 * 或 <- ,後者它是沒有結果聲明列表的函數類型,那麼每每須要用圓括號括起來,以免歧義的產生。例如:golang

*string(v)   // 等同於 *(string(v)),先將變量v表明的值轉換爲string類型的值,而後再獲取指向它的指針類型值。
(*string)(v) // 把變量v的值轉換爲指針類型*string的值。

<-chan int(v)   // 等同於 <-(chan int(v)),先將變量v表明的值轉換爲chan int類型的值,而後再今後通道類型值中接收一個int類型的值。
(<-chan int)(v) // 把變量v的值轉換爲通道類型<-chan int的值。

func()(v)     // Go語言理解爲任何無參數聲明但有一個結果聲明的匿名函數。
(func())(v)   // 把變量v的值轉換爲函數類型func()的值。
func() int(v) // 等同於(func() int)(v),把v的值轉換成一個有結果聲明的函數的類型。

對於常量 x,若是它可以被轉換爲類型 T 的值,那麼它們符合以下狀況:框架

  • x 能夠被類型T的值表明。例如,iota 能夠表示一個大於等於零的整數常量。他能夠把 uint 類型的值表明。類型表達式 uint(iota) 是合法的,它的結果值會是一個 uint 類型的常量。ide

  • x 是一個浮點數常量,T 是一個浮點數類型,而且 x 在(根據IEEE-754標準中描述的向偶數舍入規則)被舍入以後能夠被類型 T 的值表明。例如:函數

    float32(0.49999998) // 求值結果是一個float32類型的常量0.5
  • 若是 x 是一個整數常量,而且 T 是一個 string 類型,那麼將會遵循一套規則來決定類型轉換的結果。它一樣適合於很是量的值。這將在後面的 與 string類型相關的轉換 處講解。ui

  • 對於很是量 x,它可以被轉換爲類型 T 的值,那麼它們符合以下狀況:
    x 能夠被賦值給類型 T 的變量。例如:編碼

    type Computer interface {
        CpuType() string
    }
    
    type Laptop struct {
        cpuType string
    }
    
    func (self Laptop) CpuType() string {
        return self.cpuType
    }

    類型轉換表達式:指針

    // 合法,求值結果會是一個Computer類型的值。由於類型Laptop是接口類型Computer的一個實現類型
    Computer(Laptop{cpuType: "Intel Core i5"})
  • x 的類型和類型 T 的潛在類型是相等的。例如:code

    type MyString string
    // 類型轉換表達式
    MyString("Huazie") // 合法,類型MyString的潛在類型就是string類型。
  • x 的類型和類型 T 都是未命名的指針類型,而且它們的基本類型(指向那個值的類型)的潛在類型是相等的。例如:

    var str1 string
    // 類型轉換表達式
    (*string)(&str1) // 合法,求值結果是一個*MyString類型的值。
  • x 的類型和類型 T 都是整數類型或都是浮點數類型。例如:

    var i32 uint32
    var f32 folat32
    // 類型轉換表達式
    int64(i32) // 合法。
    float64(f32) // 合法。
  • x 的類型和類型 T 都是複數類型。例如:

    var comp64 complex64
    // 類型轉換表達式
    complex128(comp64) // 合法。
  • x 是一個整數類型值或是一個元素類型爲 byterune 的切片類型值,且 T 是一個 string 類型。例如:

    string([]byte{'a'}) // 合法,求值結果是string類型值"a"。
  • x 是一個 string 類型值,且T是一個元素類型爲 byterune 的切片類型。

    []rune("Huazie") // 合法

2. 數值類型之間的轉換

能夠經過常量聲明或者數據類型轉換把一個int類型的變量,數值常量1024無類型的,例如:

var number int = 1024

或把數值常量 1024 賦給一個 int 類型的變量:

int(1024)

對於很是量的數值類型值,規則以下:

  • 當把一個整數類型值從須要較少二進制位表示的整數類型轉換到須要較多二進制位表示的整數類型(好比從 int8 類型轉換到 int16 類型)的時候 : 若是這個整數類型值是有符號的,那麼該符號位上的(最左邊的)那個二進制值將做爲擴展項填充在轉換過程當中新增的那些二進制位上,不然將會把 0 做爲擴展項進行填充。這種擴展方式是針對整數類型值的補碼而言的。例如:int16 類型值 -32767 的十六進制表示是 0xffff 。它的補碼是 0x8001 。此補碼最左邊的二級制位上的二級制值是 1。若是要把這個 int16 類型值轉換爲 int32 類型值,就須要用最左邊的這個值 1 填充在高位一側新增的那16個二進制位上。類型轉換以後的補碼是 0xffff8001 。在這個補碼之上再求其補碼以得其原碼,即 0x80007fff 。此原碼錶示的就是十進制數 -32767 ,類型轉換前的那個數值相等。

  • 當把一個整數類型值從須要較多二級制位表示的整數類型轉換到須要較少二級制位表示的整數類型的時候,須要把多餘的若干個較高位置的二進制值裁掉,而只保留與目標類型所需二進制位數至關的若干個較低位置的二進制值。例如,int16 類型值 -32767,若是要把它轉換爲一個 int8 類型值,就須要對其補碼 0x8001 截取較低 8 爲的二進制值,獲得 0x01。因爲此值的最左邊的二進制位上是 0,因此它自己就是類型轉換總會獲得一個有效的數值。但對於整數常量來講,這樣的類型轉換就會形成一個編譯錯誤。例如,類型轉換表達式 int8(-32767) 會使編譯器報錯,由於整數常量 -32767 超出了 int8 類型所能表示的數值範圍。

  • 當把一個浮點數類型值向整數類型值進行轉換的時候,該浮點數類型值的小數部分將被抹去。例如,若是有一個 float32 類型的變量 f32 且其值爲 -32767.345 ,那麼類型表達式 int32(f32) 的求值結果爲 -32767 。若是浮點數類型值在被抹去小數位以後超出了目標整數類型的表示範圍,那麼該值還會被截短。例如,在類型表達式 int8(f32) 被求值的過程當中會首先 float32 類型值 -32767.345 的小數部分卻去掉,而後再將其中較高的 24 位的二進制值截掉,最終獲得結果 1

  • 當把一個整數或浮點數轉換爲一個浮點數類型的值或者把一個複數轉換爲一個複數類型的值的時候,該值將會被依據目標類型的精度進行舍入操做。例如,在 float32 類型的變量 x 中存儲的值可能會超出 IEEE-754 標準中規定的 32 位(二進制值表明的)浮點數的精度。可是,類型表達式 float32(x) 的求值結果必定會是 x 的值向32位浮點數的精度轉化以後的值。算術表達式 x + 0.1 的結果值可能會超出32位浮點數的精度,可是類型轉換表達式 float32(x + 0.1) 的求值結果卻不會這樣。

在很是量的浮點數類型值或複數類型值的類型轉換中,當目標類型的精度不可以知足被轉換的值的須要的時候,雖然轉換會成功,但其結果將是不肯定的,這依賴於不一樣平臺的Go語言的具體實現。

3. 與string類型相關的轉換

  • 當把一個有符號整數值或無符號整數值向字符串類型轉換的時候,將會產生出一個字符串類型值。被轉換的整數值應該是一個有效的 Unicode 代碼點的表明。在做爲結果的字符串類型值中的就是那個 Unicode 代碼點對應的字符。在底層,這個字符串類型值是由該 Unicode 代碼點的 UTF-8 編碼值表示的。若是被轉換的整數值不能表明一個有效的 Unicode 代碼點,那麼轉換結果將會是「\ufffd」,即 Unicode 字符「�」。例如:

    string(0x4e2d) // 求值結果爲「中」,其UTF-8編碼爲\xe4\xb8\xad
    string('國')   // 求值結果值爲「國」,其UTF-8編碼爲\xe5\x9b\xbd
    string(-1)     // 求值結果爲「�」,整數值-1不能表明一個有效的Unicode代碼點。

    若是有一個目標類型是 string 類型的別名類型是 MyString,那麼能夠將它視同爲 string 類型。例如:

    MyString(0x4e2d) // 等同於string(0x4e2d)
  • 當把一個元素類型爲 byte 的切片類型值向字符串類型轉換時,將會產生出一個字符串類型值。這個字符串類型值實際上就是由被轉換的切片類型值中的每一個字節類型值依次組合而成的。若是切片類型值爲 nil,那麼類型轉換的結果將會是「」。例如:

    string([]byte{'g', '\x6f', '\x6c', '\x61', 'n', 'g'})//求值結果是"golang"

    因爲使用 "\x" 爲前導並後跟兩位十六進制數能夠表示寬度爲一個字節的值,所以一個字節類型的值也就能夠由這種方法表示。若是源類型是一個 [ ]byte 類型的別名類型,那麼能夠將它視同爲 [ ]byte 類型。

  • 當把一個元素類型爲 rune 的切片類型值向字符串類型轉換時,將會產生出一個字符串類型值。這個字符串類型值實際上就是依次串聯每一個 rune 類型值後的結果。若是切片類型值爲 nil,那麼類型轉換的結果將會是「」。例如:

    string([]rune{ 0x4e2D, 0x56fd })//求值結果是"中國"

    若是源類型是一個 [ ]rune 類型的別名類型,那麼咱們能夠將它視同爲 [ ]rune 類型。

  • 當把一個字符串類型值向 [ ]byte 類型轉換時,其結果將會是把該字符串類型值按字節拆分後的結果。對於「」來講,轉換後的結果必定是 [ ]byte 類型的空值 nil 。例如:

    []byte("hello")//結果是[]byte{104, 101, 108, 108, 111}

    在這個 [ ]byte 類型值中的每一個元素都是對應字符的ASCII編碼值的十進制表示形式。若是目標類型是一個 [ ]byte 類型的別名類型,那麼能夠將它視同爲 [ ]byte 類型。

  • 當把一個字符串類型值向 [ ]rune 類型轉換時,其結果將會是把該字符串類型值按字符拆分後的結果。對於 "" 來講,轉換後的結果必定是 [ ]rune 類型的空值 nil

    []rune("中國") // 結果是[]byte{20013, 22269}

    在這個 [ ]rune 類型值中的每一個元素都是對應字符的 Unicode 代碼點的十進制表示形式。若是目標類型是一個 [ ]rune 類型的別名類型,那麼能夠將它視同爲 [ ]rune 類型。

UTF-8 這種編碼方式會把一個字符編碼爲一個或多個字節。對於同一個字符串類型值來講,與它對應的字節序列和字符序列中的元素並不必定是一 一對應的。字節序列中的單個字節並不必定能表明一個完整的字符。例如,以字符串類型值「中國」爲例:

// 字節序列的前三個元素表明了字符'中'的UTF-8編碼值,然後三個元素則表明了字符'國'的UTF-8編碼值。
[]byte{228, 184, 173, 229, 155, 189}
// 這個字符序列中的第一個元素表明了字符'中'的Unicode代碼點,而第二個元素則表明了字符'國'的Unicode代碼點。
[]byte{20013, 22269}

對於每個ASCII編碼可表示的字符來講,它的 Unicode 代碼點和 UTF-8 編碼值與其 ASCII 編碼值都分別是一致的,且它們均可以由一個字節類型值表明。對於一個包含了 ASCII 編碼可表示的字符的字符串類型值來講,與它對應的字節序列和字符序列中的元素值一定也是一一對應的。

byte 類型值和 rune 類型值都屬於整數值的一種。全部整數值均可以由十進制字面量、八進制字面量和十六進制字面量來表明。能夠把任意一種方式表示的 rune 字面量賦給任何整數類型的變量,只要該 rune 字面量對應的 Unicode 代碼點不超出那個整數類型的表示範圍。例如:

var nation int16 = '國' // '國' == 0x56fd == 22269
[]byte{ 'g', '\x6f', '0x6c', '\u0061', '\156', '\U00000067' } // 求值結果是"golang"

4. 別名類型值之間的轉換

類型是 MyStringstring 類型的別名類型。若是一個整數值分別轉換爲這兩個類型的值,將會獲得相同的結果。把一個字符串字面量賦給 MyString 類型的變量:

var ms MyString = "中國"

MyString 類型的值之上應用切片操做:

ms[1]

在某個數據類型和它的別名類型之間以及同一個數據類型的多個別名類型之間的類型轉換是合法的。而且,在這種類型轉換的過程當中並不會創造出新的值,而僅僅是變換了一下那個已存在的值的所屬類型。

結語

本篇主要介紹了Go語言數據使用中類型轉換相關的內容,下一篇咱們將會介紹Go語言的一些內建函數的使用,敬請期待!!!

最後附上知名的Go語言開源框架:

etcd: 一個高可用的鍵值存儲系統。它可被用於創建共享配置系統和服務發現系統。它的靈感來自於Apache ZooKeeper。咱們能夠在https://github.com/coreos/etcd上找到它的源碼。

相關文章
相關標籤/搜索