13

GO的第二天,赋值和类型

 4 years ago
source link: https://studygolang.com/articles/27033
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

元组赋值

赋值,一听这个词,感觉什么都不用说了,就是简单!不过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语言圣经》


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK