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 


目录
相关文章
|
4天前
|
安全 Go
Golang深入浅出之-Go语言模板(text/template):动态生成HTML
【4月更文挑战第24天】Go语言标准库中的`text/template`包用于动态生成HTML和文本,但不熟悉其用法可能导致错误。本文探讨了三个常见问题:1) 忽视模板执行错误,应确保正确处理错误;2) 忽视模板安全,应使用`html/template`包防止XSS攻击;3) 模板结构不合理,应合理组织模板以提高可维护性。理解并运用这些最佳实践,能提升Go语言模板编程的效率和安全性,助力构建稳健的Web应用。
16 0
|
23小时前
|
安全 测试技术 Go
Golang深入浅出之-Go语言单元测试与基准测试:testing包详解
【4月更文挑战第27天】Go语言的`testing`包是单元测试和基准测试的核心,简化了测试流程并鼓励编写高质量测试代码。本文介绍了测试文件命名规范、常用断言方法,以及如何进行基准测试。同时,讨论了测试中常见的问题,如状态干扰、并发同步、依赖外部服务和测试覆盖率低,并提出了相应的避免策略,包括使用`t.Cleanup`、`t.Parallel()`、模拟对象和检查覆盖率。良好的测试实践能提升代码质量和项目稳定性。
6 1
|
23小时前
|
运维 监控 Go
Golang深入浅出之-Go语言中的日志记录:log与logrus库
【4月更文挑战第27天】本文比较了Go语言中标准库`log`与第三方库`logrus`的日志功能。`log`简单但不支持日志级别配置和多样化格式,而`logrus`提供更丰富的功能,如日志级别控制、自定义格式和钩子。文章指出了使用`logrus`时可能遇到的问题,如全局logger滥用、日志级别设置不当和过度依赖字段,并给出了避免错误的建议,强调理解日志级别、合理利用结构化日志、模块化日志管理和定期审查日志配置的重要性。通过这些实践,开发者能提高应用监控和故障排查能力。
8 1
|
23小时前
|
安全 Go
Golang深入浅出之-Go语言标准库中的文件读写:io/ioutil包
【4月更文挑战第27天】Go语言的`io/ioutil`包提供简单文件读写,适合小文件操作。本文聚焦`ReadFile`和`WriteFile`函数,讨论错误处理、文件权限、大文件处理和编码问题。避免错误的关键在于检查错误、设置合适权限、采用流式读写及处理编码。遵循这些最佳实践能提升代码稳定性。
5 0
|
2天前
|
安全 Unix Go
Golang深入浅出之-Go语言中的时间与日期处理:time包详解
【4月更文挑战第26天】Go语言的`time`包提供处理日期和时间的功能,包括`time.Time`类型、时间戳、格式化与解析。本文讨论了核心概念、常见问题(如时区处理、格式字符串混淆、超时控制和并发安全)及解决方法。推荐使用`time.LoadLocation`管理时区,熟悉时间格式规则,用`context`精确控制超时,并注意并发安全。文中通过代码示例展示了如何获取格式化时间、计算时间差以及创建定时任务。学习和应用这些知识可提高程序的健壮性和准确性。
15 2
|
2天前
|
XML JSON Go
Golang深入浅出之-XML处理在Go语言中的实现:encoding/xml包
【4月更文挑战第26天】Go语言的`encoding/xml`库提供XML处理,包括序列化和反序列化。本文讨论了XML处理的基础,如`xml.Marshal`和`xml.Unmarshal`函数,以及常见问题和易错点,如标签命名、结构体嵌套、omitempty标签和命名空间。建议遵循标签命名规则,正确处理嵌套和属性,谨慎使用omitempty,以及理解并有效利用命名空间。文中还给出了基础示例和处理XML属性的代码示例,帮助读者掌握XML处理技巧。
12 1
Golang深入浅出之-XML处理在Go语言中的实现:encoding/xml包
|
2天前
|
JSON JavaScript 前端开发
Golang深入浅出之-Go语言JSON处理:编码与解码实战
【4月更文挑战第26天】本文探讨了Go语言中处理JSON的常见问题及解决策略。通过`json.Marshal`和`json.Unmarshal`进行编码和解码,同时指出结构体标签、时间处理、omitempty使用及数组/切片区别等易错点。建议正确使用结构体标签,自定义处理`time.Time`,明智选择omitempty,并理解数组与切片差异。文中提供基础示例及时间类型处理的实战代码,帮助读者掌握JSON操作。
13 1
Golang深入浅出之-Go语言JSON处理:编码与解码实战
|
2天前
|
安全 Go 开发者
Golang深入浅出之-Go语言模板(text/template):动态生成HTML
【4月更文挑战第25天】Go语言的`text/template`和`html/template`库提供动态HTML生成。本文介绍了模板基础,如基本语法和数据绑定,以及常见问题和易错点,如忘记转义、未初始化变量、复杂逻辑处理和错误处理。建议使用`html/template`防止XSS攻击,初始化数据结构,分离业务逻辑,并严谨处理错误。示例展示了条件判断和循环结构。通过遵循最佳实践,开发者能更安全、高效地生成HTML。
8 0
|
3天前
|
中间件 Go API
Golang深入浅出之-Go语言标准库net/http:构建Web服务器
【4月更文挑战第25天】Go语言的`net/http`包是构建高性能Web服务器的核心,提供创建服务器和发起请求的功能。本文讨论了使用中的常见问题和解决方案,包括:使用第三方路由库改进路由设计、引入中间件处理通用逻辑、设置合适的超时和连接管理以防止资源泄露。通过基础服务器和中间件的代码示例,展示了如何有效运用`net/http`包。掌握这些最佳实践,有助于开发出高效、易维护的Web服务。
15 1
|
3天前
|
数据管理 Go 开发者
Golang深入浅出之-Go语言上下文(context)包:处理取消与超时
【4月更文挑战第25天】Go语言中的`context`包在并发、网络请求和长任务中至关重要,提供取消、截止时间和元数据管理。本文探讨`context`基础,如`Background()`、`TODO()`、`WithCancel()`、`WithDeadline()`和`WithTimeout()`。常见问题包括不当传递、过度使用`Background()`和`TODO()`以及忽略错误处理。通过取消和超时示例,强调正确传递上下文、处理取消错误和设置超时以提高应用健壮性和响应性。正确使用`context`是构建稳定高效Go应用的关键。
12 1