函数
- 函数返回值有命名,可以使用返回值命名做运算,并且返回时,只需要写一个return即可
func rectProps(length, width float64)(area, perimeter float64) {
area = length * width
perimeter = (length + width) * 2
return //no explicit return value
}
可变参数函数
- 注意点:
- 形式:func fname(a int, b … int){} 这的b就是可变参数,其实就是在类型前面加 …
- 只有函数的最后一个参数可以是可变的
- 可变参数的类型是切片 比如[]int,
- 如果可变参数没有实参,那么就是默认值,也就是切片的默认值,nil slice,其长度和容量都是0。
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)
}
- 可变参数与切片参数的区别
既然可变参数本身就会被转换成一个切片,接收不定个数的元素,那为何不直接用切片,切片也是可以满足任意个数元素的??
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, []int{89, 90, 95})
find(45, []int{56, 67, 45, 90, 109})
find(78, []int{38, 56, 98})
find(87, []int{})
}
- 上面这段代码,与再上面的一段代码对比,我们可以得出可变参数的一些优势:
- 减少了每次函数调用都需要创建slice的麻烦,每次的函数调用,我们都需要创建一个新的slice。而使用可变参数函数就可以避免slice的创建,从而简化代码的开发。
- 在上一个程序的最后一行即:find(87, []int{}),我们创建了一个空数组,就是为了满足find的函数定义。这在可变参数函数中完全是不必的。当使用可变参数函数时,我们只需要写个find(87)就行了。
- 使用可变参数的程序相对于使用slice的程序来说,可读性更强。
Append是一个可变参数函数
当使用append函数向一个slice中追加值时,为什么append函数可以接收任意数目的实参。这是因为,append函数其实是一个可变函数:
func append(slice []Type, elems ...Type) []Type
传递slice给可变参数函数
我们知道可变参数是一个切片slice,那么如果我们再传一个切片进去,可以吗?(答案:不可以)
func find(num int, nums ...int) {
}
func main() {
nums := []int{89, 90, 95}
find(89, nums) // 报错:cannot use nums (type []int) as type int in argument to find。
}
- 那么有没有办法传递slice给可变参数呢?
- 有的,用语法糖,在实参后面加上…
func find(num int, nums ...int) {
}
func main() {
nums := []int{89, 90, 95}
find(89, nums...) // 编译通过
}
传递slice给可变参数函数传的是地址
package main
import (
"fmt"
)
func change(s ...string) {
s[0] = "Go"
}
func main() {
welcome := []string{"hello", "world"}
change(welcome...)
fmt.Println(welcome) // 结果是[]string {"Go", "world"}
}
- 可以看出,函数传递的都是值,只不过这里把地址作为值传入,所以里面改变,外面也会跟着改变
- 再来看个易错的例子:
package main
import (
"fmt"
)
func change(s ...string) {
s[0] = "Go"
s = append(s, "playground")
fmt.Println(s) // 打印出 [Go world playground]
}
func main() {
welcome := []string{"hello", "world"}
change(welcome...)
fmt.Println(welcome) // 打印出 [Go world]
}