类型推断
类型推断(Type Inference)是编程语言在编译时自动解释表达式中数据类型的能力,通常在函数式编程的语言(例如Haskell)中存在。类型推断的优势主要在于可以省略类型,这使编程变得更加容易。
明确地指出变量的类型在编程语言中很常见,编译器在多大程度上支持类型推断因语言而异。例如,某些编译器可以推断出变量、函数参数和返回值的类型。如图3-1所示,Go语言提供了特殊的操作符“:=”用于变量的类型推断。
类型推断的优势
语言支持类型推断有两个主要的优势。一是如果使用得当,那么它可以使代码更易阅读。
二是如果类型更加复杂,那么类型推断的价值变得显而易见。在许多情况下,这将减少代码中的冗余信息。
类型推断还具有动态语言的灵活特性
尽管如此,显式地指出类型仍可以让编译器更轻松地了解代码实际应执行的操作,而不会犯任何错误。
Go语言中类型推断的特性
每个语言的类型推断能力各不相同,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
小结
Go语言中对变量使用简单的类型推断,给人以编写动态类型代码的感觉,同时仍然具有静态类型的安全性。在实现方法上,类型推断借鉴了编译时的原理。类型推断涉及编译时词法解析和抽象语法树阶段。处理常量时,先采用math/big库进行高精度处理,再在SSA阶段转换为Go语言中预置的标准类型(int,float64)。