函数

  1. 函数返回值有命名,可以使用返回值命名做运算,并且返回时,只需要写一个return即可
func rectProps(length, width float64)(area, perimeter float64) {
    area = length * width
    perimeter = (length + width) * 2
    return //no explicit return value
}

可变参数函数

  1. 注意点:
  • 形式: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)
  }
  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() {
    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]
}