可变参数这么玩,装逼指南!Go语言可变参数技巧解密

简介: 可变参数这么玩,装逼指南!Go语言可变参数技巧解密

/ Go 语言可变参数指南 /

可变参数是 Go 语言一个非常实用的特性,可以实现函数接收可变个数的参数。本文将全面介绍可变参数的用法。本文主要内容如下

  1. 可变参数函数定义
  2. 调用可变参数函数
  3. 可变参数为 slice 类型
  4. 与普通 slice 参数的区别
  5. 固定参数与可变参数组合使用
  6. 多个可变参数函数的错误用法
  7. nil 可变参数的错误用法
  8. 反射获取可变参数信息
  9. 与接口类型可变参数的行为差异
  10. 错误的使用方式
  11. 实际应用场景
  12. 其他语言的可变参数
  13. 语言设计的取舍


1

 

一、可变参数函数定义

在函数参数列表中,可以使用省略号...来标识一个可变参数:

func myFunc(arg1 int, arg2 string, args ...float64) {}

这里args是一个可变参数,它可以接收零个或多个float64类型的参数。


2

 

二、调用可变参数函数

调用一个可变参数函数时,有两种传参方式:

  1. 按位置传参
myFunc(1, "hello") // 不传递可变参数 
myFunc(1, "hello", 1.1, 2.2) // 传递2个可变参数
  1. 通过 args 参数名传参
myFunc(1, "hello", args...[1.1, 2.2, 3.3])

可变参数既支持位置传参,也支持名称传参。


3

 

三、可变参数为 slice 类型

在函数内部,可变参数作为一个切片([]T)使用:

func myFunc(args ...int) {
  fmt.Printf("可变参数类型:%T\n", args) // []int
}

可以通过 range 遍历可变参数 slice:

func sum(values ...int) int {
  total := 0
  for _, val := range values {
    total += val
  }
  return total
}

也可以直接访问 slice 元素:values[0]


4

 

四、与普通 slice 参数的区别

可变参数函数其实就是语法糖,更优雅地支持了 slice 参数:

// 可变参数函数  
func sum(nums ...int) {}
// 对应普通slice参数
func sum(nums []int) {} 

可变参数比直接的 slice 参数更加简洁、直观。


5

 

五、固定参数与可变参数组合使用

可变参数非常灵活,可以与固定参数组合使用:

func concat(sep string, args ...string) {}

同时接受固定长度参数和可变参数。

调用时,可以按位置传参:

concat("-", "a", "b", "c")

或者通过 args 关键字传参:

concat("-", args...["a", "b", "c"])


6

 

六、多个可变参数函数的错误用法

需要注意,一个函数只能定义一个可变参数:

func myfunc(arg1 ...string, arg2 ...int) {} // 错误,不能定义多个可变参数

这是因为多个可变参数无法区分参数边界。

正确的定义方式:

func myfunc(arg1 ...interface{}) {} // 一个可变参数


7

 

七、nil 可变参数的错误用法

传入的可变参数不能为 nil 切片:

func myfunc(arg ...int) {}
myfunc(nil) // 错误,不能传入nil

    这是因为 nil 切片的元素类型是不确定的。


    8

     

    八、反射获取可变参数信息

    通过反射,可以获取可变参数的类型信息:

    import "reflect"
    func myfunc(args ...interface{}) {
      t := reflect.TypeOf(args) // []interface{}
      fmt.Println(t)  
    }

    这样在运行时就可以推断出实际的可变参数类型。


    9

     

    九、与接口类型可变参数的行为差异

    如果可变参数是接口类型,与普通类型会有一些差异:

    func myfunc(args ...interface{}) {
      for _, arg := range args {
        fmt.Println(arg) // 每个参数都是接口类型 
      }
    }

    需要进行类型断言来获取实际类型。


    10

     

    十、错误的使用方式

    以下是一些错误的可变参数使用方式:

    • 定义多个可变参数
    • 可变参数不能为 nil
    • 类型不匹配
    • 可变参数必须在最后

    需要注意避免这类错误用法。


    11

     

    十一、实际应用场景

    可变参数特别适合以下几种场景:

    • 不确定参数个数的函数
    • 格式化输出函数如 fmt.Printf
    • 列表处理函数如 strings.Join
    • 最大值最小值等统计类函数
    • 异常记录处理函数

    等等。


    12

     

    十二、其他语言的可变参数

    12.1

     

    C 语言

    C 语言使用va_listva_start、va_end处理可变参数:

    void print(int n,...) {
      va_list args;
      va_start(args, n);
      for(int i = 0; i < n; i++) {
        int arg = va_arg(args, int);
        printf("%d\n", arg);
      }
      va_end(args); 
    }

    稍微繁琐,不如 Go 语言优雅简洁。

    12.2

     

    Java

    Java 使用三点运算符表示可变参数:

    void print(String... args) {
    } 

    但统一隐式转换为 Object 数组,存在类型安全隐患。

    12.3

     

    Python

    Python 使用*args表示位置可变参数:


    def print(*args):

    但 args 为元组,类型不确定。

    12.4

     

    JavaScript

    JS 函数没有类型定义,所有参数本质上都是可变参数。


    13

     

    十三、语言设计的取舍

    可变参数有利有弊,语言设计需要做出取舍:

    13.1

     

    优点

    • 使用简单统一
    • 灵活方便
    • 类型安全

    13.2

     

    缺点

    • 参数类型隐藏
    • 调试不易
    • 性能损耗


    14

     

    总结

    Go 语言可变参数功能强大,同时又不失简洁与类型安全。正确合理使用可变参数函数,可以大大提升代码质量和开发效率。


    目录
    相关文章
    |
    5月前
    |
    存储 安全 Java
    【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
    结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
    308 3
    |
    编译器 Go
    揭秘 Go 语言中空结构体的强大用法
    Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
    |
    运维 监控 算法
    监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
    在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
    |
    7月前
    |
    Cloud Native 安全 Java
    Go:为云原生而生的高效语言
    Go:为云原生而生的高效语言
    453 1
    |
    7月前
    |
    Cloud Native Go API
    Go:为云原生而生的高效语言
    Go:为云原生而生的高效语言
    508 0
    |
    7月前
    |
    Cloud Native Java Go
    Go:为云原生而生的高效语言
    Go:为云原生而生的高效语言
    340 0
    |
    7月前
    |
    Cloud Native Java 中间件
    Go:为云原生而生的高效语言
    Go:为云原生而生的高效语言
    387 0
    |
    7月前
    |
    Cloud Native Java Go
    Go:为云原生而生的高效语言
    Go:为云原生而生的高效语言
    426 0
    |
    7月前
    |
    数据采集 Go API
    Go语言实战案例:多协程并发下载网页内容
    本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
    |
    7月前
    |
    数据采集 JSON Go
    Go语言实战案例:实现HTTP客户端请求并解析响应
    本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。

    热门文章

    最新文章