前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >传个参数都有坑,我蚌埠了!

传个参数都有坑,我蚌埠了!

作者头像
程序员小饭
发布2023-02-24 15:08:38
1810
发布2023-02-24 15:08:38
举报
文章被收录于专栏:golang+phpgolang+php

最近在工作中发现一个坑,关键是这个坑还不报错,所以在此记录一下,顺便也对相关知识点做一个总结。

关于这个坑,还得从「不定参数」说起

不定参数

不定参数,顾名思义,也就是「参数个数不确定」的时候golang支持的一种机制

举个例子

我们想实现一个多个数字累加的方法,既然是多个数字,那么数字的个数肯定是不确定的,所以我们可以如下编写

代码语言:javascript
复制

func NumberSum(args ...int) (res int) { //不定参数的使用示例
 for i := range args {
    res += i
 }
 return res
}

func main() {
 total := NumberSum(1, 2, 3, 4, 5, 6)
 fmt.Println(total)
}
//输出结果
15

通过上面的示例我们可以看出不定参数的使用还是很简单的,只要在参数定义的时候,在「类型前面加上三个点」就可以了。但是不定参数在使用的时候还有其他需要注意的问题需要注意一下。

  • 所有的不定参数类型必须是相同的
  • 不定参数必须是函数的最后一个参数。
  • 不定参数在函数体内相当于一个切片,对切片的操作同样适合对不定参数的操作。(比如上述例子中,是可以对args做「for range」操作的)
  • 切片也可以作为参数传递给不定参数,切片名称后面要加上“...”。

前面三点其实还是比较好理解的,针对第四点看看下面例子,也是「容易出问题」的地方,而且本文要说的「坑」也和这个有关

代码语言:javascript
复制
func NumberSum(args ...int) (res int) {
 for i := range args {
  res += i
 }
 return res
}

func main() {
  //定义了一个切片,准备传给不一定参数
 numSelice := []int{1, 2, 3, 4, 5, 6}  
  //把切片传给不定参数的时候,需要在参数后面加上...
 total := NumberSum(numSelice...)
 fmt.Println(total)
}

通过上述例子咱们应该已经对不定参数有了一定的掌握,接下来咱们看一个特殊的场景 如果「不定参数的各个参数类型不一样」怎么办?这种场景其实还是很常见的,用interface类型即可解决。比如我们要封装一个生成rediskey的方法,

代码语言:javascript
复制
func MakeRedisKey(key string, args ...interface{}) (redisKey string) {
  redisKey = fmt.Sprintf(key, args)
 return redisKey
}

func main() {
   ucid := 123
   name := "test"
   key := "key_id_%d_name_%s"
   redisKey := MakeRedisKey(key, ucid, name)
   fmt.Println(redisKey)
}
//输出结果
key_id_[123 %!d(string=test)]_name_%!s(MISSING)

上面的代码看似没有问题,但是输出结果却看似来就像乱码一样,这是为什么呢?我们来分析一下

  • 我们在main函数中调用「MakeRedisKey」函数的时候传进去的「ucid和name」都为不定参数
  • 「在MakeRedisKey函数中」,打印出来的args的类型为「切片」类型,也就是 []interface {}
  • 我们看一下「fmt.Sprintf」函数的定义
代码语言:javascript
复制
func Sprintf(format string, a ...interface{}) string {
 ........内容是什么不重要
 return s
}

我们会发现Sprintf的第二个参数也是「不定参数」

这就相当于在「MakeRedisKey」中,我们拿着「切片类型」的参数args,去传给一个「不定参数」作为参数,按照我们上面总结的**把切片传给不定参数的时候,需要在参数后面加上...**这条定律,上面代码改成如下即可正常

代码语言:javascript
复制
func MakeRedisKey(key string, args ...interface{}) (redisKey string) {
 redisKey = fmt.Sprintf(key, args...)  //在args后面加上...
 return redisKey
}
func main() {
 ucid := 123
 name := "test"
 key := "key_id_%d_name_%s"
 redisKey := MakeRedisKey(key, ucid, name)
 fmt.Println(redisKey)
}
//输出结果
key_id_123_name_test

这样我们就可以得到正常的结果了。最后总结一下,「我们在使用不定参数的时候,尤其是涉及到多次传递的时候,一定不要想当然,记得在中间传递过程中在参数后面加上...」

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-12-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员小饭 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 不定参数
    • 举个例子
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档