package main
type Celsius float64 // 摄氏温度
type Fahrenheit float64 // 华氏温度
const (
AbsoluteZeroC Celsius = -273.15 // 绝对零度
FreezingC Celsius = 0 // 结冰点温度
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) }
我们在这个包声明了两种类型:Celsius和Fahrenheit分别对应不同的温度单位。它们虽然有 着相同的底层类型float64,但是它们是不同的数据类型,因此它们不可以被相互比较或混在 一个表达式运算。刻意区分类型,可以避免一些像无意中使用不同单位的温度混合计算导致 的错误。
1. 有两种方式来转换
(1)一个类似Celsius(t)或Fahrenheit(t)形式的显式转型操作才能将float64转为 对应的类型。Celsius(t)和Fahrenheit(t)是类型转换操作,它们并不是函数调用。类型转换不 会改变值本身,但是会使它们的语义发生变化。
(2)CToF和FToC两个函数则是对不同 温度单位下的温度进行换算,它们会返回不同的值。
对于上面的第一种:每一个类型T,都有一个对应的类型转换操作T(x),用于将x转为T类型(译注:如果T是 指针类型,可能会需要用小括弧包装T,比如 (*int)(0) )。只有当两个类型的底层基础类型 相同时,才允许这种转型操作,或者是两者都是指向相同底层结构的指针类型,这些转换只 改变类型而不会影响值本身。如果x是可以赋值给T类型的值,那么x必然也可以被转为T类 型,但是一般没有这个必要。
2. 运算
底层相同的变量可以进行运算:
fmt.Printf("%g\n", BoilingC-FreezingC) // "100" °C
boilingF := CToF(BoilingC)
fmt.Printf("%g\n", boilingF-CToF(FreezingC)) // "180" °F
fmt.Printf("%g\n", boilingF-FreezingC) // compile error: type mismatch
3.比较
底层相同的变量可以进行比较:
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"!
4.其他
许多类型都会定义一个String方法,因为当使用fmt包的打印方法时,将会优先使用该类型对 应的String方法返回的结果打印,
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
func main() {
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
}