golang中的四種類型轉換總結

go類型轉換

go存在4種類型轉換分別爲:斷言、強制、顯式、隱式。golang

一般說的類型轉換是指斷言,強制在平常不會使用到、顯示是基本的類型轉換、隱式使用到可是不會注意到。斷言、強制、顯式三類在go語法描述中均有說明,隱式是在平常使用過程當中總結出來。c#

斷言類型轉換

斷言經過判斷變量是否能夠轉換成某一個類型函數

類型斷言

Type assertions語法文檔 鏡像地址性能

一個簡單的斷言表達式:測試

var s = x.(T)ui

若是x不是nil,且x能夠轉換成T類型,就會斷言成功,返回T類型的變量s。若是T不是接口類型,則要求x的類型就是T,若是T是一個接口,要求x實現了T接口。google

若是斷言類型成立,則表達式返回值就是T類型的x,若是斷言失敗就會觸發panic。指針

上述表所示再斷言失敗就會panic,go提供了另一種帶返回是否成立的斷言語法:code

s, ok := x.(T)接口

該方法和第一種差很少同樣,可是ok會返回是否斷言成功不會出現panic,ok就表示是不是成功了。

類型switch

go語法種還提供了另一種類型switch的斷言方法。

Type switches語法文檔 鏡像地址

x斷言成了type類型,type類型具體值就是switch case的值,若是x成功斷言成了某個case類型,就能夠執行那個case,此時i := x.(type)返回的i就是那個類型的變量了,能夠直接看成case類型使用。

switch i := x.(type) {
case nil:
    printString("x is nil")                // type of i is type of x (interface{})
case int:
    printInt(i)                            // type of i is int
case float64:
    printFloat64(i)                        // type of i is float64
case func(int) float64:
    printFunction(i)                       // type of i is func(int) float64
case bool, string:
    printString("type is bool or string")  // type of i is type of x (interface{})
default:
    printString("don't know the type")     // type of i is type of x (interface{})
}

強制類型轉換

強制類型轉換經過修改變量類型

該方法不常見,主要用於unsafe包和接口類型檢測,須要懂得go變量的知識。

unsafe

本文檔僅大概說明一下,具體研究請求查找相關資料。unsafe語法文檔 鏡像地址

var f float64
bits = *(*uint64)(unsafe.Pointer(&f))

type ptr unsafe.Pointer
bits = *(*uint64)(ptr(&f))

var p ptr = nil

float64就強制轉換成uint64類型,float的地址就是一個值可是類型是float64,而後建立了一個uint64類型變量,地址值也是float64的地址值,兩個變量值相同類型不一樣,強制轉換了類型。

unsafe強制轉換是指針的底層操做了,用c的朋友就很熟悉這樣的指針類型轉換,利用內存對齊才能保證轉換可靠,例如int和uint存在符號位差異,利用unsafe轉換後值可能不一樣,可是在內存存儲二進制如出一轍。

接口類型檢測

例以下列代碼:

var _ Context = (*ContextBase)(nil)

nil的類型是nil地址值爲0,利用強制類型轉換成了*ContextBase,返回的變量就是類型爲*ContextBase地址值爲0,而後Context=xx賦值若是xx實現了Context接口就沒事,若是沒有實如今編譯時期就會報錯,實現編譯期間檢測接口是否實現。

顯示類型轉換

Conversions語法文檔 鏡像地址

一個顯式轉換的表達式T(x) ,其中T是一種類型而且x是可轉換爲類型的表達式T,例如:uint(666)

在如下任何一種狀況下,變量x均可以轉換成T類型:

  • x能夠分配成T類型。
  • 忽略struct標籤x的類型和T具備相同的基礎類型。
  • 忽略struct標記x的類型和T是未定義類型的指針類型,而且它們的指針基類型具備相同的基礎類型。
  • x的類型和T都是整數或浮點類型。
  • x的類型和T都是複數類型。
  • x的類型是整數或[]byte或[]rune,而且T是字符串類型。
  • x的類型是字符串,T類型是[]byte或[]rune。

例以下列代碼利用了規則進行轉換,規則實現能夠參考reflect.Value.Convert方法邏輯:

int64(222)
[]byte("ssss")

type A int
A(2)

隱式類型轉換

隱式類型轉換平常使用並不會感受到,可是運行中確實出現了類型轉換,如下列出了兩種。

組合間的從新斷言類型

type Reader interface {
    Read(p []byte) (n int, err error)
}
type ReadCloser interface {
    Reader
    Close() error
}
var rc ReaderClose
r := rc

ReaderClose接口組合了Reader接口,可是r=rc的賦值時仍是類型轉換了,go使用系統內置的函數執行了類型轉換。之前遇到過相似接口組合類型的變量賦值,而後使用pprof和bench測試發現了這一細節,在接口類型轉移時浪費了一些性能

相同類型間賦值

type Handler func()

func NewHandler() Handler {
    return func() {}
}

雖然type定義了Handler類型,可是Handler和func()是兩種實際類型,類型不會相等,使用反射和斷言均會出現兩種類型不一樣

二者類型不一樣驗證代碼:

package main

import (
    "fmt"
    "reflect"
)

type Handler func()

func a() Handler {
    return func() {}
}

func main() {
    var i interface{} = main
    _, ok := i.(func())
    fmt.Println(ok)
    _, ok = i.(Handler)
    fmt.Println(ok)
    fmt.Println(reflect.TypeOf(main) == reflect.TypeOf((*Handler)(nil)).Elem())
}

// true
// false
// false
相關文章
相關標籤/搜索