14 Go的类型转换
作者:mmseoamin日期:2023-12-05

概述

        在上一节的内容中,我们介绍了Go的错误处理,包括:errors包、返回错误、抛出异常、捕获异常等。在本节中,我们将介绍Go的类型转换。在Go语言中,类型转换是一种将一个值从一种类型转换为另一种类型的过程。类型转换主要有3种,分别为:断言类型转换、显式类型转换、隐式类型转换。下面将分别进行介绍。

断言类型转换

        在Go语言中,断言是一种类型转换,它可以将一个接口类型的值转换为具体的类型。断言在Go语言中通常用于类型检查和类型转换,其语法如下:

          value, ok := interfaceValue.(Type)

        其中,interfaceValue是一个接口类型的值,Type是要转换的具体类型。断言将接口值转换为具体类型,并将转换后的值赋给value变量。同时,还返回一个布尔值ok,指示转换是否成功。注意:断言只能用于接口类型的值转换为具体类型,如果尝试将一个非接口类型的值进行断言,将会导致编译错误。

        在下面的示例代码中,我们定义了一个接口类型的变量data,并将其赋值为66。然后,我们使用断言将data转换为int类型,并将转换后的值赋给value变量。如果转换成功,打印出转换后的值;否则,打印出转换失败的消息。接下来,我们尝试将data转换为string类型,并进行了类似的处理。

package main
import "fmt"
func main() {  
    var data interface{} = 66
    // 断言将接口值转换为int类型,输出:Convert to int success: 66
    value, ok := data.(int)
    if ok {
        fmt.Println("Convert to int success:", value)
    } else {
        fmt.Println("Convert to int  failed")
    }
    // 断言将接口值转换为string类型,输出:Convert to string failed
    value2, ok2 := data.(string)
    if ok2 {
        fmt.Println("Convert to string success:", value2)
    } else {
        fmt.Println("Convert to string failed")
    }
}

        另外,我们还可以使用switch语句结合断言进行类型转换。通过将接口类型的值与特定类型的值进行比较,可以实现类型转换。具体如何使用,可参考下面的示例代码。

package main
import "fmt"
func main() {  
    var data interface{} = "Hello, CSDN"
    // 断言switch,输出:Convert to string: Hello, CSDN
    switch value := data.(type) {
    case int:
        fmt.Println("Convert to int:", value)
    case string:
        fmt.Println("Convert to string:", value)
    default:
        fmt.Println("Convert failed")
    }
}

        注意:使用断言进行类型转换时,如果断言失败,将会进入default分支。因此,在使用断言时,建议始终添加default分支以处理可能的错误情况。

显式类型转换

        显式类型转换可以通过使用类型转换操作符将一个值转换为指定的类型,其语法如下:

          type_name(expression)

        其中,type_name为数据类型,expression为表达式或变量值。注意:类型转换可能会导致精度损失或溢出。因此,在进行类型转换时,需要确保目标类型能够容纳原始值的范围,否则可能会产生不正确的结果。

        在下面的示例代码中,我们将一个float64类型的值66.66显式地转换为int类型,并将结果赋给变量y。由于int类型无法容纳小数部分,故转换后的值为66。

package main
import "fmt"
func main() {
    var x float64 = 66.66
    // 将float64类型的变量显式转换为int类型
    var y int = int(x)
    // 输出: 66
    fmt.Println(y)
}

隐式类型转换

        隐式类型转换是指在表达式中自动进行的类型转换,这种类型转换通常发生在不同类型的数据之间进行运算时。Go语言会自动将它们转换成相同的类型,以确保表达式的合法性和正确性。要真正理解隐式类型转换,需要先了解下常量。

        常量是指不能改变值的特殊变量,分为两种:未命名常量和命名常量。未命名常量只在编译期间存在,不会存储在内存中。命名常量存在于内存静态区,不允许修改。比如:const a = 66这条语句,66是未命名常量,a是命名常量;编译后,a的值固定为66,而等号右边的66不再存在。

        除位运算、未命名常量外,运算符两边的操作数类型必须相同,否则会发生编译错误。如果运算符两边是不同类型的未命名常量,则隐式转换的优先级为:整数(int) < 字符型(rune) < 浮点数(float) < 复数(Complex)。

package main
import "fmt"
func main() {
    // 66和100的类型相同,不需要隐式类型转换
    const num1 = 66 / 100
    // 整数优先转换为浮点数100.0, 结果为0.66
    const num2 = 66 / 100.0
    
    const num3 int = 88
    // num3为命名常量,与1.5的数据类型不同,无法进行隐式类型转换,会发生编译错误
    const num4 = num3 * 1.5
    fmt.Println(num1, num2, num3, num4)
}

        另外,兼容的类型可以进行隐式类型转换,不兼容的类型不能够进行隐式类型转换,具体可参考下面的示例代码。

package main
import "fmt"
func main() {
    // 类型相同,不需要隐式类型转换
    const num1 int = 66
    // 66.0即为66,类型兼容,可进行隐式类型转换
    const num2 int = 66.0
    // 类型不兼容,不能进行隐式类型转换,会发生编译错误
    const num3 int = 66.1
    // 类型相同,不需要隐式类型转换
    const num4 float64 = 66.0
    // 66即为66.0,类型兼容,可进行隐式类型转换
    const num5 float64 = 66
    fmt.Println(num1, num2, num3, num4, num5)
}

strconv包

        strconv包是Go语言标准库中的一个包,它提供了字符串和基本数据类型之间的转换函数。这个包中的函数可以将字符串转换为不同的基本数据类型(比如:整数、浮点数等),也可以将基本数据类型转换为字符串。

        以下是strconv包中一些常用的函数:

        Atoi(s string) (int, error):将字符串s转换为对应的整数。如果转换失败,会返回一个错误值。

        ParseInt(s string, base int, bitSize int) (int, error):将字符串s转换为对应的整数,并指定进制base和位数 bitSize。如果转换失败,会返回一个错误值。

        ParseFloat(s string, bitSize int) (float64, error):将字符串s转换为对应的浮点数,并指定位数bitSize。如果转换失败,会返回一个错误值。

        FormatInt(v int64, base int) string:将整数v转换为指定进制的字符串表示。

        FormatFloat(v float64, fmt byte, prec, bitSize int) string:将浮点数v转换为字符串表示,并指定格式化选项 fmt、精度prec和位数bitSize。第二个参数fmt是格式化选项,'f'表示使用普通的浮点数格式。第三个参数prec是精度,-1表示使用尽可能多的精度。第四个参数bitSize是浮点数的位数,64位浮点数为float64。

        关于这些函数具体如何使用,可以参考下面的示例代码。

package main
import "fmt"
import "strconv"
func main() {
    // 将字符串转换为整数,输出:66
    num, err := strconv.Atoi("66")
    if err != nil {
        fmt.Println("Failed:", err)
    } else {
        fmt.Println(num)
    }
    // 将字符串转换为浮点数,输出:3.14
    fnum, err := strconv.ParseFloat("3.14", 64)
    if err != nil {
        fmt.Println("Failed:", err)
    } else {
        fmt.Println(fnum)
    }
    
    // 将整数转换为字符串,输出:99
    str := strconv.Itoa(99)
    fmt.Println(str)
    // 将浮点数转换为字符串,输出:2.718
    str = strconv.FormatFloat(2.71828, 'f', 3, 64)
    fmt.Println(str)
}