一文教你如何用好GO语言变长参数

 更新时间:2023年09月10日 08:35:20   作者:阿兵云原生  
对于函数重载相信编码过的 xdm 肯定不会陌生,那么我们一起分别来看看 C 语言,C++ 语言,GO 语言 如何去模拟和使用重载,感兴趣的可以学习一下

函数重载

对于函数重载相信编码过的 xdm 肯定不会陌生,函数重载就是在同一个作用域内定义多个具有相同名称但参数列表不同的函数

此处的参数列表不同,可以是参数的类型不同,参数的个数不同

那么我们一起分别来看看 C 语言,C++ 语言,GO 语言 如何去模拟和使用重载,体会一下

C语言模拟重载

那么我们以前学过的 C 语言,是不支持重载的,是不会自动根据参数类型来进行匹配的,但是我们可以通过一些技巧来模拟函数重载,例如我们可以定义一类名字相似的函数,参数列表来模拟重载的效果

例如:

  • 定义函数 sum_int ,参数为 2 个 int 类型的变量
  • 定义函数 sum_double ,参数为 2 个 double 类型的变量
  • 定义函数 sum_float ,参数为 2 个 float 类型的变量
int sum_int(int x, int y) {
    return x + y;
}
double sum_int(double x, double y) {
    return x + y;
}
float sum_int(float x, float y) {
    return x + y;
}

那么在调用的时候,我们就会根据不同的入参类型来调用对应的函数

C++ 重载

又如我们写 C++ 的时候,这个语言是支持重载的,我们可以在调用函数的时候,传入不同的参数类型,不同的参数个数来决定我们需要调用哪个函数的具体实现,我们来看看如何来使用重载

例如:

  • 定义一个函数 getinfo ,参数为 int 类型的变量
  • 还是 getinfo 函数,参数为 double 类型的变量
  • 还是 getinfo 函数,参数为 string 类型的变量
void getinfo (int x) {
    std::cout << "int 类型入参: " << x << std::endl;
}
void getinfo (double x) {
    std::cout << "double 类型入参: " << x << std::endl;
}
void getinfo (std::string x) {
    std::cout << "std::string 类型入参: " << x << std::endl;
}

使用 C++ 的时候,我们可以看到,使用同一个函数,咱们直接就可以传入不同类型的入参,来应用重载

GO语言模拟重载

那么,GO 语言本身也是不允许重载的,因为GO语言的设计理念就是简洁和易读,这样可以避免代码的复杂和可维护性

不过我们在使用的时候,为了我们实现我们不同的业务场景,可以使用GO 语言中的变长参数来进行模拟

例如:

  • 定义一个函数 overloadTest,参数为一个变长参数,参数类型为 ...interface{}
  • 那么,对于这个函数,我们参数个数和参数类型,都可以按照我们的需求进行传递即可
func overloadTest(name string, hobby ...interface{}){
    for _,v :=range hobby {
       switch v.(type) {
       case int,int8,int16,int32,int64,uint,uint8,uint16,uint32,uint64:
         fmt.Printf("%s love 整数  -- %+v \n",name, v)
       case string:
          fmt.Printf("%s love 字符串 -- %+v \n",name, v)
       case []int:
         tmpInts := v.([]int)
          fmt.Printf("%s love 整型切片 -- %+v \n",name, tmpInts)
       default:
          fmt.Printf("%s  not love type  -- %+v \n",name, v)
       }
    }
}
func main(){
   overloadTest("xiaozhu", "learning", "playing")
   overloadTest("xiaozhu", []int{1,2,3,4})
   overloadTest("xiaozhu", map[string]int{"apple":2000})
   overloadTest("xiaozhu", 100)
}

可以看到 GO 语言公共库中使用变长参数的地方还是非常多的,例如打印相关的

fmt 包中的 Printf

fmt 包中的 Println

还有我们使用切片时经常使用的 append 函数

使用变长参数的的场景还是不少的,可以多留意咱们的公共库,用起来也是非常的方便,我们需要对变长参数的设计和实现要有更多的理解,用起来才能够得心应手

GO 语言中的变长参数

对于 GO 语言中的变长参数定义为:函数调用时指可以接受 0 个,1 个或者多个实际参数的函数

此处的定义,是否看上去和重载的定义稍微相似呢?

例如上述的 GO 语言的demo,给函数中传入变长参数的时候,我们就是在参数列表中写入 ...T ,那么很明显,一个函数中只能有一个这样的边长参数,且这个参数需要放到参数列表的最后一个

否则 GO 语言就不知道你传入的哪一些参数是属于变长参数的入参值了,xdm 们可以思考一下,如果这个变长参数放到参数列表的开头,或者参数列表的中间,那么我们在传递参数的时候,如何去识别呢?

我们可以来实际演示一波:

  • 定义一个函数,变长参数列表类型为 string,且放到参数列表最后
  • 同样的函数,将变长参数列表放到第一个
  • 同样的函数,将变长参数列表放到第二个

这里实际上可以看到,变长参数的本质实际上就是一个切片类型的实例,函数内部实现,就是将这个参数作为切片来进行处理的,这也得益于切片的长度不是固定的

这里需要注意的一点:

函数定义了变长参数,我们在传递的时候可以一个一个的传,也可以使用切片变量后加... 的方式来传递,但是这两种传递方式不能混合使用,只能取其一

如何实现参数可选和默认参数呢?

思考一下,变长参数我们知道如何使用了,如何实现默认参数和可选参数呢?

实际上就是咱们在实现的时候,在函数内部控制我们需要必须传递的可选参数(实际是切片类型)最小的长度,或者最大的长度,然后去读取相应位置的值即可

这一点 xdm 感兴趣的可以参考上述 GO 语言demo 来实现一下默认参数和可选参数哦,通过去校验变长参数的长度,数据类型就可以做到这一点,可以在评论区留下的 demo 哦

还记得 grpc 中的功能选项模式吗

在 GO 语言中,微服务的开发相信我们使用的不会少,那么在使用 grpc 通信的时候,我们就可以发现处理 rpc 接口的时候,我们是可以传递拦截器的,这个参数,就是功能选项模式

我们可以仿照它弄一个我们自己的功能选项模式:

现在汽车打价格战,疯狂的卖车,我们就用给车加选装来作为例子来体验选项模式的实现:

定义一台车,属性有颜色,座椅,品牌,风格,能源 其中部分配置是选装,也可以不选

type ABINGCar struct{
   Brand string
   Style string
   MarshmallowChair int   // 棉花糖座椅
   Color string
   Power string
}

给选装的配置,写好对应的选项功能

type Option func(*ABINGCar)
func WithStyle(style string)Option{
   return func(a *ABINGCar){
      a.Style = style
   }
}
func WithMarshmallowChair(enable int)Option{
   return func(a *ABINGCar){
      a.MarshmallowChair = enable
   }
}
func WithPower(power string)Option{
   return func(a *ABINGCar){
      a.Power = power
   }
}

New 一台车出来,写一个 NewCar,加上选项功能

func NewCar(options ...Option) *ABINGCar{
   car := &ABINGCar{
      Color: "red",
      Brand: "abing brand",
   }
   for _,option := range options{
      option(car)
   }
   return  car
}

在 main 函数中,去买车,买不同的车,可以选装不同的配置,想咋选咋选

到此这篇关于一文教你如何用好GO语言变长参数的文章就介绍到这了,更多相关go变长参数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 使用Go实现优雅重启服务功能

    使用Go实现优雅重启服务功能

    这篇文章主要介绍了如何使用Go来实现优雅重启服务,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-11-11
  • 一文教你如何快速学会Go的struct数据类型

    一文教你如何快速学会Go的struct数据类型

    结构是表示字段集合的用户定义类型。它可以用于将数据分组为单个单元而不是将每个数据作为单独的值的地方。本文就来和大家聊聊Go中struct数据类型的使用,需要的可以参考一下
    2023-03-03
  • 深入理解Go高级并发模式编写更高效可扩展的应用程序

    深入理解Go高级并发模式编写更高效可扩展的应用程序

    Go对并发提供了强大的原生支持,本文讨论Go的高级并发模式,理解这些并发模式,可以帮助我们编写高效的Go应用程序,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-02-02
  • 深入理解go unsafe用法及注意事项

    深入理解go unsafe用法及注意事项

    go虽然是一种高级语言,但是也还是给开发者提供了指针的类型unsafe.Pointer,我们可以通过它来直接读写变量的内存,本文来了解一下 unsafe 里所能提供的关于指针的一些功能,以及使用unsafe.Pointer的一些注意事项
    2024-01-01
  • Go anko实现支持脚本语言

    Go anko实现支持脚本语言

    anko是一个可以让 Go 项目支持脚本语言的小工具,换句话说,就是可以给 Go 项目加点“脚本魔法”,下面就跟随小编一起来学习一下他的具体使用吧
    2024-11-11
  • 如何在 Go语言中使用日志包

    如何在 Go语言中使用日志包

    这篇文章主要介绍了如何在 Go语言中使用日志包,日志文件就是一种快速找到这些 bug,更好地了解程序工作状态的方法,下文基于go语言介绍该详细需要的小伙伴可以参考一下
    2022-04-04
  • Go Context库 使用基本示例

    Go Context库 使用基本示例

    在Go的http包中,每个请求由独立的goroutine处理,这些goroutine可能需要访问请求特定的数据或启动其他服务,Context在Go语言中提供了一种方式来传递请求域的数据、取消信号和截止时间,本文介绍Go Context库 使用基本示例,感兴趣的朋友跟随小编一起看看吧
    2024-09-09
  • Golang开发之字符串与切片问题踩坑记录

    Golang开发之字符串与切片问题踩坑记录

    字符串和切片,都是golang常用的两种内置数据类型,最近在日常工作中,遇到了一个字符串切片导致的问题,记录一下排查问题的过程,避免后续在这种场景上踩坑
    2023-07-07
  • 详解Golang time包中的结构体time.Ticker

    详解Golang time包中的结构体time.Ticker

    在日常开发过程中,会频繁遇到对时间进行操作的场景,使用 Golang 中的 time 包可以很方便地实现对时间的相关操作,接下来的几篇文章会详细讲解 time 包,本文讲解一下 time 包中的结构体 time.Ticker,需要的朋友可以参考下
    2023-08-08
  • 详解Golang语言HTTP客户端实践

    详解Golang语言HTTP客户端实践

    本文主要介绍了Golang语言HTTP客户端实践,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11

最新评论