可变参数函数

一、可变参数函数

1. 概念

  • 可变参数相当于python中定义的函数它的参数中args的功能,用来接收多个参数,而参数中带有可变参数的函数就叫可变参数函数

2. 语法

  • 而Go中可变参数是用 ...T 来表示的,而且只能加在函数参数的最后,表示这个函数可以接收任意个(0到无数个) T 类型的参数作为最后一个参数(即只有函数的最后一个参数才允许时可变的

3. 工作原理

  • 可变参数函数的工作原理是把接收的多余参数全部转换为一个新的切片,再将这个切片当作一个参数传给函数

二、创建一个可变参数函数

创建了一个可变参数函数find ,

package main

import (
    "fmt"
)

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)
    found := false
    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            found = true
        }
    }
    if !found {
        fmt.Println(num, "not found in ", nums)
    }
    fmt.Printf("\n")
}
func main() {
    find(89, 89, 90, 95)
    find(45, 56, 67, 45, 90, 109)
    find(78, 38, 56, 98)
    find(87)  // 不给可变参数nums传参
}

/*
这里的 find(89, 89, 90, 95) ,函数中的可变参数 ...int 将 89, 90, 95 编译转换为一个int类型的切片 []int{89, 90, 95} ,然后传给函数find的参数 nums

find(45, 56, 67, 45, 90, 109) ,函数中的可变参数 ...int 将 56, 67, 45, 90, 109 编译转换为一个int类型的切片 []int{56, 67, 45, 90, 109} ,然后传给函数find的参数 nums

这里的 find(87) ,函数中的可变参数 ...int 将 空 编译转换为一个int类型的空切片 []int{} ,然后传给函数find的参数 nums,我们仅传给find 函数一个参数。我们没有给可变参数 nums ...int 传入任何参数。这也是合法的,在这种情况下 nums 是一个长度和容量为 0 的 nil 切片

打印结果:
type of nums is []int
89 found at index 0 in [89 90 95]

type of nums is []int
45 found at index 2 in [56 67 45 90 109]

type of nums is []int
78 not found in  [38 56 98]

type of nums is []int
87 not found in  []

*/

三、给可变参数函数传入切片

1. 错误示范

  • 在二中我们给可变参数传的都属于单个元素,单个元素转换成切片是没有问题的,但是当我们直接给可变参数传入切片会怎么样呢
package main

import (
    "fmt"
)

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)
    found := false
    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            found = true
        }
    }
    if !found {
        fmt.Println(num, "not found in ", nums)
    }
    fmt.Printf("\n")
}
func main() {
    nums := []int{89, 90, 95}
    find(89, nums)
}

/*
结果是程序报错了,无法这样传值,main.go:23: cannot use nums (type []int) as type int in argument to find
其实原因很简单,find函数定义的可变参数为 ...int ,意思可以接收int类型的参数,然后将这些int类型参数转化成切片,而我们此时传入的是切片,在转换切片时格式为[]int{nums},这里之所以会失败是因为 nums 是一个 []int类型 而不是 int类型
*/

2. 正确写法

  • 按照上面的错误示范,的确是不能传切片的,但是有没有别的方法能实现呢,答案是肯定的
  • 这个方法就是在传切片的时候,在切片后加上 ... 后缀,这样做之后,切片将直接传入函数,相当于给可变参数带句话,让可变参数不再创建新的切片
  • 这里提醒一句,由于切片和其底层数组的关系,当你在函数中修改切片时,请确保你知道你自己在做什么
package main

import (
    "fmt"
)

func find(num int, nums ...int) {
    fmt.Printf("type of nums is %T\n", nums)
    found := false
    for i, v := range nums {
        if v == num {
            fmt.Println(num, "found at index", i, "in", nums)
            found = true
        }
    }
    if !found {
        fmt.Println(num, "not found in ", nums)
    }
    fmt.Printf("\n")
}
func main() {
    my_nums := []int{89, 90, 95}
    find(89, my_nums...)  // 在 切片my_nums 后面加上 ...  即可实现给可变参数传切片
}

(1)函数中修改传入的切片

package main

import (
    "fmt"
)

func change(s ...string) {
	s[0] = "Go"
	s = append(s, "playground")
	fmt.Println("s:", s, len(s), cap(s))
}

func main() {
	welcome := []string{"hello", "world"}
	change(welcome...)
	fmt.Println("welcome:", welcome, len(welcome), cap(welcome))
}

/*
打印结果
s: [Go world playground] 3 4
welcome: [Go world] 2 2

切片s 和 切片 welcome 的底层数组都是同一个为 [2]string{"hello", "world"} ,
当s[0]= "Go" 对切片值修改时,此时底层数组也会发生变化,底层数组变为 [2]string{"Go", "world"} ,
当 对s 切片进行追加时,由于追加后切片长度大于原底层数组,所以要创建新的底层数组,但是又因为原来的底层数组还有切片 welcome 在引用,所以无法被回收,
此时 s切片的底层数组变为 长度为4(变为原底层数组的2倍)的新底层数组,所以打印的s 信息变为[Go world playground] 3 4
*/

posted @ 2024-02-23 14:49  BigSun丶  阅读(155)  评论(0)    收藏  举报