设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间14 现在时间14 缓存数据 她的声音可以讲故事,温柔中带着力量。

她的声音可以讲故事,温柔中带着力量。 -- 大眠

查看: 1492|回复: 2

一文带你了解Golang中类型转换库cast的使用

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:231
  • 打卡月天数:0
  • 打卡总奖励:3948
  • 最近打卡:2025-04-04 05:05:20
等级头衔

等級:晓枫资讯-上等兵

在线时间
5 小时

积分成就
威望
0
贡献
437
主题
405
精华
0
金钱
5269
积分
906
注册时间
2023-1-7
最后登录
2025-5-31

发表于 2023-3-1 19:09:05 来自手机 | 显示全部楼层 |阅读模式
0 前言

你是否在使用 Go 的过程中因为类型转换的繁琐而苦恼过?
你是否觉得 Go 语言中的类型断言可能会 panic 而对自己写的代码有那么一点点不放心?
如果你有过如上体验,并且想要找到一个合适的解决方案的话,那么本文推荐的一个用于类型转换的第三方库 cast 绝对是一个值得尝试的选择。

1 cast

cast 是一个极为简洁的第三方库,github 地址:https://github.com/spf13/cast。
项目主页里的头两句介绍就是:
  1. Easy and safe casting from one type to another in GoDon’t Panic! ... Cast
复制代码
可见,cast 的主要功能就是类型转换,且没有 panic
多说一句,
  1. Don't panic
复制代码
在英语中本身就是一个常用语,表示不要慌张、不要害怕,所以,在这里其实是一个有意思的双关。

2 上手


2.1 安装引入

这里只讲
  1. go mod
复制代码
的引入方式。
  1. go.mod
复制代码
文件中
  1. require github.com/spf13/cast v1.5.0
复制代码
(目前最新版为 1.5.0),接着用
  1. mod
复制代码
进行
  1. download
复制代码
  1. tidy
复制代码
等操作,再在代码中
  1. import "github.com/spf13/cast"
复制代码
即可使用
  1. cast
复制代码
关键字使用 cast 的功能了。

2.2 使用

2.2.1 常规用法
我们直接通过几个简单的例子来体验一下 cast:
  1. var target interface{} = "123"
  2. str := "hello, world!"

  3. fmt.Println(cast.ToString(target))
  4. fmt.Println(cast.ToInt(target))
  5. fmt.Println(cast.ToInt(str))

  6. // 输出:
  7. 123
  8. 123
  9. 0
复制代码
我们创建了一个
  1. interface{}
复制代码
类型的变量
  1. target
复制代码
,传统方式下如果要将一个
  1. interface{}
复制代码
转化为
  1. string
复制代码
,需要使用类型断言:
  1. var target interface{} = "123"

  2. str := target.(string)
  3. // or
  4. str, ok := target.(string)
复制代码
类型断言的缺点很明显,如果不接收第二个返回值,会有 panic 风险;如果接收第二个参数,则略显繁琐。
到了第二个
  1. ToInt
复制代码
,cast 的优势就更明显了,传统方式下,一个
  1. interface{}
复制代码
类型的
  1. "123"
复制代码
如果要转换成
  1. int
复制代码
,必须先类型断言为
  1. string
复制代码
,再使用
  1. strconv
复制代码
转换成
  1. int
复制代码
,代码就不写了,想象一下就知道有多麻烦,而 cast 可以将这个过程一步到位。
接着是第三个输出
  1. cast.ToInt(str)
复制代码
,这里的
  1. str
复制代码
是一个
  1. string
复制代码
类型的
  1. "hello, world!"
复制代码
,它显然不能被转换成
  1. int
复制代码
,于是 cast 将其设置为
  1. int
复制代码
的零值
  1. 0
复制代码

其实 cast 的所有类型转换都会将无法转换的结果转为零值,而不是 panic,这也就是 cast 官方承诺的
  1. Don't panic
复制代码

2.2.2 带 error 的用法
看到这里,有朋友可能要问了:如果我的逻辑必须判断目标是否转换成功了呢?如果我的转换结果就有可能是 0 呢?我怎么知道这个 0 是转换失败的零值,还是目标原始的真实值?
cast 的作者自然也想到了这一点,于是,cast 的所有类型转换函数都有一个对应的
  1. with error
复制代码
版:
  1. str := "hello"
  2. strNum := "123"

  3. num, e := cast.ToIntE(str)
  4. fmt.Println(num)
  5. fmt.Println(e)

  6. num, e = cast.ToIntE(strNum )
  7. fmt.Println(num)
  8. fmt.Println(e)

  9. // 输出
  10. 0
  11. unable to cast "hello" of type string to int64
  12. 123
  13. nil
复制代码
  1. error
复制代码
的版本其实就是在非
  1. error
复制代码
版的函数名结尾添加了一个
  1. E
复制代码
,其结果也很好理解,这里不再展开细讲了。
2.2.3 很酷的东西
最后再来看一个我觉得很酷的东西:
  1. var js interface{} = `{"name": "Jack", "gender": "male"}`

  2. fmt.Println(cast.ToStringMap(js))

  3. // 输出
  4. map[gender:male name:Jack]
复制代码
cast 能直接将一个 JSON 字符串转换成
  1. map
复制代码
!当然这一步其实用类型断言也可以做到,但 cast 的方式会更加优雅。

3 性能及原理

如果你只是想使用 cast,那么接下来的内容就可以忽略了;如果你还想深入了解一些 cast,可以看看这一节。
很多做后端开发的朋友会习惯性关心性能和原理,我也一样,所以早在我第一次接触使用 cast 时,我就去看了它的源码,然后……这样,我直接把上面我们用过的
  1. ToInt
复制代码
的相关源码列出来,大家自己看看就明白了:
  1. // cast.go

  2. // ToInt casts an interface to an int type.
  3. func ToInt(i interface{}) int {
  4.     v, _ := ToIntE(i)
  5.     return v
  6. }

  7. // caste.go

  8. // ToIntE casts an interface to an int type.
  9. func ToIntE(i interface{}) (int, error) {
  10.     i = indirect(i)    // 这个 indirect 函数里使用反射来获取 i 的 interface{} 值,代码不列了
  11.     // ...省略
  12.     switch s := i.(type) {
  13.     case int64:
  14.         return int(s), nil
  15.     case int32:
  16.         return int(s), nil
  17.     // ...省略
  18.     case string:
  19.         v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
  20.         if err == nil {
  21.             return int(v), nil
  22.         }
  23.         return 0, fmt.Errorf("unable to cast %#v of type %T to int64", i, i)
  24.     }
  25.     // ...省略
  26. }
复制代码
明白了吧,没有什么技巧,依然是常规手段进行转换,只是它把各种情况都囊括了进来,做到了足够全面。
而且我们发现,带
  1. error
复制代码
的函数才是原始函数,不带
  1. error
复制代码
的只是一个封装后的便捷方式。
cast 的源码很短,只有两个文件,加起来不到 2000 行。
所以看到这里,cast 的性能问题就没什么值得讨论的了,一定高不到哪儿去。尤其在泛型已经实装了之后,泛型的性能要远超类型断言、反射之类的技术,因此大家在使用 cast 的时候也请视情况而定。

4 总结

cast 是我用了很多年的一个库了,早在泛型还八字没一撇的时候我就发现了这个库,那时我们的项目代码里充斥着许多
  1. interface{}
复制代码
和反射,cast 的确帮了我们很大的忙。尽管现在已经是泛型时代,go 语言可以用性能更佳的泛型替代许多以前只能用
  1. interface{}
复制代码
甚至反射实现的场景,但依然存在不少我们无法避免要用
  1. interface{}
复制代码
类型转换的地方,这种时候,尤其是这段程序对性能不敏感时,cast 依然是一把万金油式的利器。
总结一下,cast 是一个用于类型转换的 golang 第三方库,它最大的特点是在类型转换时可以不 panic,而是将出现问题的地方转换成零值。当然,cast 也提供了带
  1. error
复制代码
的函数,以供开发者在适当情况下使用。cast 的性能可能会是一个问题,因此我们在使用时一定要选择合适的场景,避免由于滥用 cast 造成的性能瓶颈。
到此这篇关于一文带你了解Golang中类型转换库cast的使用的文章就介绍到这了,更多相关Golang类型转换库cast内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
17
积分
14
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2024-10-17 20:10:25 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
18
积分
16
注册时间
2022-12-27
最后登录
2022-12-27

发表于 2025-3-1 20:13:33 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表