Golang 语言的编程技巧之类型

简介: Golang 语言的编程技巧之类型

介绍

Golang 语言是一门静态类型的编程语言,我们在编写代码时,为了提升代码的灵活性,有时会使用空接口类型,对于空接口类型的变量,一般会通过类型断言判断变量的类型,而且可能还会遇到需要类型转换的场景。本文我们就来介绍一下类型断言、类型转换和类型选择。

编程技巧

类型断言

类型断言提供了访问接口类型值的底层具体值的方式,这里需要注意的是被类型断言的值必须是接口类型的值。类型断言返回两个值,被断言的接口类型值的底层具体值和一个表示是否断言成功的布尔类型的值。

t, ok := i.(T)

我们在上一篇介绍变量的文章中,介绍过类型推断,并通过列举一个示例证明使用类型推断可以使代码提升可维护性和健壮性。但是使用类型推断的代码也有缺点,我们先看一下这两段代码。

未使用类型断言:

func main () {
    id := getVal(1)
    // id := getVal("a")
    fmt.Println(id)
}
func getVal (val interface{}) interface{} {
    return val
}

使用类型断言:

func main () {
    id := getVal(1)
    // id := getVal("a")
    id, ok := id.(int);
    if !ok {
        err := errors.New("illegal parameter")
        fmt.Println(err)
        return
    }
    fmt.Println(id)
}
func getVal (val interface{}) interface{} {
    return val
}

阅读上面这两段代码,main 函数中都是通过调用 getVal() 函数,使用类型推断的方式给变量 id 赋值。不同的是 main 函数,第一段代码中未使用类型断言,第二段代码中使用了类型断言。所以第一段代码的 main 函数如果调用 getVal() 函数时传递非整型参数,也可以正常输出;第二段代码的 main 函数如果调用 getVal() 函数时传递非整型参数,将会被断言代码拦截。

类型转换

类型转换的表达式 T(v),将 v 转换为类型 T。关于类型转换,我们需要注意的“坑”如下所示:

整型之间的转换:

func main () {
    var a int
    a = 128
    b := int8(a)
    fmt.Println(b) // -128
}

阅读上面这段代码,int 类型的变量 a 赋值为 128,将变量 a 转换为 int8 类型的变量 b,输出变量 b 的结果是 -128,原因是 int 类型和 int8 类型的取值范围不同。

浮点型转换为整型:

func main () {
    var a float64
    a = 3.1415926
    b := int(a)
    fmt.Println(b) // 3
}

阅读上面这段代码,浮点型 float64 的变量 a,转换为 int 类型的变量 b,输出结果是 3,变量 a 值的小数部分被截掉了。

整型转换为字符串类型:

func main () {
    var a int
    a = -1
    b := string(a) // conversion from int to string yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)
    fmt.Println(b) // �
}

阅读上面这段代码,int 类型变量 a,转换为 string 类型变量 b,变量 b 的输出结果是 ,表示未知字符,原因是 Unicode 码点(code point)中没有 -1。

字符串类型和切片(字节切片和字符切片)类型互相转换:

func main () {
    var a string
    a = "编程"
    b := []byte(a)
    fmt.Println(b) // [231 188 150 231 168 139]
    c := []rune(a)
    fmt.Println(c) // [32534 31243]
}

阅读上面这段代码,将字符串类型的变量 a 分别转换为字节切片类型变量 b 和字符切片类型变量 c,它们的输出结果不同,原因是 UTF-8 编码一个中文汉字是 3 个字节, 3 个字节代表 1 个字符。而字符切片类型的元素本身就是 Unicode 字符。

类型选择

最后我们再介绍一下类型选择(type switch),也有人翻译为类型切换。它是一种按照顺序从几个类型断言中选择分支的结构,类型选择与 switch 语句类似,但是类型选择中的 case 不是值,而是值的类型。

func main () {
    var a interface{}
    // a = 1
   // a = "golang"
   a = false
    switch val := a.(type) {
        case int:
            fmt.Printf("val:%d type:%T\n", val, val)
        case string:
            fmt.Printf("val:%s type:%T\n", val, val)
        default:
            fmt.Printf("unknow type:%T\n", val)
    }
}

阅读上面这段代码,我们使用 type switch 判断空接口类型变量 a 的实际数据类型是否为我们预定义的类型之一。

03

总结

本文我们介绍了 Golang 语言类型相关的编程技巧,通过使用类型断言、类型转换和类型选择,可以使我们的代码更加灵活。

推荐阅读:

Golang 语言的编程技巧之变量

Golang 语言中的非类型安全指针

参考资料:

https://tour.go-zh.org/methods/15 

https://golang.org/ref/spec#Conversions 

https://tour.go-zh.org/basics/13 

https://liyucang-git.github.io/2019/06/17/彻底弄懂Unicode编码/

https://tour.go-zh.org/methods/16 


目录
相关文章
|
2月前
|
Go
Golang语言之管道channel快速入门篇
这篇文章是关于Go语言中管道(channel)的快速入门教程,涵盖了管道的基本使用、有缓冲和无缓冲管道的区别、管道的关闭、遍历、协程和管道的协同工作、单向通道的使用以及select多路复用的详细案例和解释。
110 4
Golang语言之管道channel快速入门篇
|
2月前
|
Go
Golang语言文件操作快速入门篇
这篇文章是关于Go语言文件操作快速入门的教程,涵盖了文件的读取、写入、复制操作以及使用标准库中的ioutil、bufio、os等包进行文件操作的详细案例。
66 4
Golang语言文件操作快速入门篇
|
2月前
|
Go
Golang语言之gRPC程序设计示例
这篇文章是关于Golang语言使用gRPC进行程序设计的详细教程,涵盖了RPC协议的介绍、gRPC环境的搭建、Protocol Buffers的使用、gRPC服务的编写和通信示例。
101 3
Golang语言之gRPC程序设计示例
|
2月前
|
安全 Go
Golang语言goroutine协程并发安全及锁机制
这篇文章是关于Go语言中多协程操作同一数据问题、互斥锁Mutex和读写互斥锁RWMutex的详细介绍及使用案例,涵盖了如何使用这些同步原语来解决并发访问共享资源时的数据安全问题。
86 4
|
2月前
|
Go 调度
Golang语言goroutine协程篇
这篇文章是关于Go语言goroutine协程的详细教程,涵盖了并发编程的常见术语、goroutine的创建和调度、使用sync.WaitGroup控制协程退出以及如何通过GOMAXPROCS设置程序并发时占用的CPU逻辑核心数。
50 4
Golang语言goroutine协程篇
|
2月前
|
Prometheus Cloud Native Go
Golang语言之Prometheus的日志模块使用案例
这篇文章是关于如何在Golang语言项目中使用Prometheus的日志模块的案例,包括源代码编写、编译和测试步骤。
51 3
Golang语言之Prometheus的日志模块使用案例
|
1月前
|
前端开发 中间件 Go
实践Golang语言N层应用架构
【10月更文挑战第2天】本文介绍了如何在Go语言中使用Gin框架实现N层体系结构,借鉴了J2EE平台的多层分布式应用程序模型。文章首先概述了N层体系结构的基本概念,接着详细列出了Go语言中对应的构件名称,包括前端框架(如Vue.js、React)、Gin的处理函数和中间件、依赖注入和配置管理、会话管理和ORM库(如gorm或ent)。最后,提供了具体的代码示例,展示了如何实现HTTP请求处理、会话管理和数据库操作。
30 0
|
2月前
|
Go
Golang语言错误处理机制
这篇文章是关于Golang语言错误处理机制的教程,介绍了使用defer结合recover捕获错误、基于errors.New自定义错误以及使用panic抛出自定义错误的方法。
46 3
|
2月前
|
Go
Golang语言之函数(func)进阶篇
这篇文章是关于Golang语言中函数高级用法的教程,涵盖了初始化函数、匿名函数、闭包函数、高阶函数、defer关键字以及系统函数的使用和案例。
58 3
Golang语言之函数(func)进阶篇
|
2月前
|
Go
Golang语言之函数(func)基础篇
这篇文章深入讲解了Golang语言中函数的定义和使用,包括函数的引入原因、使用细节、定义语法,并通过多个案例展示了如何定义不返回任何参数、返回一个或多个参数、返回值命名、可变参数的函数,同时探讨了函数默认值传递、指针传递、函数作为变量和参数、自定义数据类型以及返回值为切片类型的函数。
59 2
Golang语言之函数(func)基础篇