Go 語言 - 類型推斷解析 [1]

Don’t do it. Do it, but don’t do it again. Do it less. Do it later. Do it when they’re not looking. Do it concurrently. Do it cheaper.

類型推斷(Type Inference)是編程語言在編譯時自動解釋表達式中數據類型的能力,通常在函數式編程的語言(例如 Haskell)中存在。類型推斷的優勢主要在於可以省略類型,這使編程變得更加容易。

明確地指出變量的類型在編程語言中很常見,編譯器在多大程度上支持類型推斷因語言而異。例如,某些編譯器可以推斷出變量、函數參數和返回值的類型。如圖所示,Go 語言提供了特殊的操作符 “:=” 用於變量的類型推斷。

圖  := 操作符用於變量類型推斷

類型推斷的優勢

語言支持類型推斷有兩個主要的優勢。一是如果使用得當,那麼它可以使代碼更易閱讀。例如,可以將 C ++ 代碼

vector<int> v;
vector<int>::iterator itr = v.iterator();

變爲

vector<int> v;
auto itr = v.iterator();

二是如果類型更加複雜,那麼類型推斷的價值變得顯而易見。在許多情況下,這將減少代碼中的冗餘信息。

類型推斷還具有動態語言的靈活特性,例如 Haskell 語言的如下代碼,不管變量 x 是什麼類型,加 1 並返回結果。

succ x = x + 1

儘管如此,顯式地指出類型仍可以讓編譯器更輕鬆地瞭解代碼實際應執行的操作,而不會犯任何錯誤。

Go 語言中類型推斷的特性

如上所述,每個語言的類型推斷能力是不相同的,Go 語言的目標是減少在其他靜態類型語言中存在的混亂情況,Go 語言的設計者認爲 Java 或 C++ 中的類型系統過於複雜。因此,在設計 Go 語言時,他們對變量使用簡單的類型推斷,給人以編寫動態類型代碼的感覺,同時仍然保留靜態類型的好處。

Go 語言的類型推斷目前還相對簡單,沒有涵蓋參數和返回值之類的內容。在實踐中,可以通過在聲明新變量或常量時忽略類型信息或使用:= 表示法來觸發 Go 語言中的類型推斷。例如,在 Go 語言中,以下三個語句是等效的。

var a int = 10
var a = 10
a := 10

以 a := 333 爲例,變量 a 最終會被推斷爲 int 類型,可以用 Printf 的 %T 格式化打印出 a 的類型,輸出結果爲 type:int。

a :=  333
fmt.Printf("type:%T",a)

由於 Go 語言的類型系統禁止了不同類型之間的轉換(第 4 章中的常量除外),由於下例中的 a 已經被推斷爲 int 類型,不能夠賦值給 int64 類型。

func main() {
    a:=333
    var b int64
    b = a
}

Go 語言的類型推斷在處理包含變量標識符的推斷方面是半智能的。本質上,編譯器不允許對變量標識符引用的值進行強制類型轉換,舉幾個例子:

下面這段代碼能夠正常運行,並且 a 的類型爲 float64。

a := 1 + 1.1

下面的代碼仍然正確,a 會被推斷爲浮點數,1 會被轉換爲浮點數與 a 的值相加。

a := 1.1
b := 1 + a

但是,下面代碼是錯誤的,即 a 的值已被推斷爲整數,而 1.1 爲浮點數,不能將 a 強制轉換爲浮點數,相加失敗。編譯器報錯:constant 1.1 truncated to integer。

a := 1
b := a + 1.1

下面的例子犯了相同的錯誤,編譯器提示類型不匹配:invalid operation: a + b (mismatched types int and float64)。

a := 1
b := 1.1
c := a + b

在下一篇文章中,將介紹類型推斷的原理, see you~

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/Nz4zLHyZrEDtu5EZSt_Nlg