元组赋值
赋值,一听这个词,感觉什么都不用说了,就是简单!不过Go还提供了一个元组赋值。元组赋值是另一种形式的赋值语句,它允许同时更新多个变量的值。在赋值之前,赋值语句右边的所有表达式将会先进行求值,然后再统一更新左边对应变量的值。不BB,先看代码:
// 交换两个变量的值
x, y = y, x
a[i], a[j] = a[j], a[i]
计算两个整数值的的最大公约数(GCD)
func gcd(x, y int) int {
for y != 0 {
x, y = y, x%y
}
return x
}
计算斐波纳契数列(Fibonacci)的第N个数
func fib(n int) int {
x, y := 0, 1
for i := 0; i < n; i++ {
x, y = y, x+y
}
return x
}
是不是很方便?如果你用php去写,是不是这样写 list ( $a, $b ) = array ($b, $a );
。感受一下
可赋值性
可赋值性的规则对于不同类型有着不同要求。对于目前我们已经讨论过的类型,它的规则是简单的:类型必须完全匹配,nil可以赋值给任何指针或引用类型的变量。
类型
一个类型声明语句创建了一个新的类型名称,和现有类型具有相同的底层结构。新命名的类型提供了一个方法,用来分隔不同概念的类型,这样即使它们底层类型相同也是不兼容的。
type 类型名字 底层类型
类型声明语句一般出现在包一级,因此如果新创建的类型名字的首字符大写,则在外部包也可以使用。
为了说明类型声明,我们将不同温度单位分别定义为不同的类型:
package main
import "fmt"
type Celsius float64 // 摄氏温度
type Fahrenheit float64 // 华氏温度
const (
AbsoluteZeroC Celsius = -273.15 // 绝对零度
FreezingC Celsius = 0 // 结冰点温度
BoilingC Celsius = 100 // 沸水温度
)
func main() {
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) // mismatched types Fahrenheit and Celsius
var c Celsius
var f Fahrenheit
fmt.Println(c == 0) // "true"
fmt.Println(f >= 0) // "true"
// fmt.Println(c == f) // mismatched types Fahrenheit and Celsius
fmt.Println(c == Celsius(f)) // "true"!
}
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
,但是它们是 不同的数据类型
,因此它们 不可以
被相互比较或混在一个表达式运算。
对于每一个类型T,都有一个对应的类型转换操作T(x),用于将x转为T类型(如果T是指针类型,可能会需要用小括弧包装T,比如(*int)(0))。只有当两个类型的 底层基础类型相同
时,才允许这种转型操作,或者是两者都是指向 相同底层结构
的指针类型,这些转换只改变类型而不会影响值本身。如果x是可以赋值给T类型的值,那么x必然也可以被转为T类型
下面的声明语句,Celsius类型的参数c出现在了函数名的前面,表示声明的是Celsius类型的一个名叫String的方法,该方法返回该类型对象c带着°C温度单位的字符串:
func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
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
参考
《GO语言圣经》
有疑问加站长微信联系(非本文作者)