Go语言之函数

Posted 感觉会是有趣的事物

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言之函数相关的知识,希望对你有一定的参考价值。

  • 1. 函数定义

    • 1.1.1. golang函数特点:

    • 1.1.2. 函数声明:


1. 函数定义

1.1.1. golang函数特点:

 
   
   
 
  1. 无需声明原型。

  2. 支持不定 变参。

  3. 支持多返回值。

  4. 支持命名返回参数。

  5. 支持匿名函数和闭包。

  6. 函数也是一种类型,一个函数可以赋值给变量。


  7. 不支持 嵌套 (nested) 一个包不能有两个名字一样的函数。

  8. 不支持 重载 (overload)

  9. 不支持 默认参数 (default parameter)。

1.1.2. 函数声明:

函数声明包含一个函数名,参数列表, 返回值列表和函数体。如果函数没有返回值,则返回列表可以省略。函数从第一条语句开始执行,直到执行return语句或者执行函数的最后一条语句。

函数可以没有参数或接受多个参数。

注意类型在变量名之后 。

当两个或多个连续的函数命名参数是同一类型,则除了最后一个类型之外,其他都可以省略。

函数可以返回任意数量的返回值。

使用关键字 func 定义函数,左大括号依旧不能另起一行。

 
   
   
 
  1. func test(x, y int, s string) (int, string) {

  2. // 类型相同的相邻参数,参数类型可合并。多返回值必须用括号。

  3. n := x + y

  4. return n, fmt.Sprintf(s, n)

  5. }

函数是第一类对象,可作为参数传递。建议将复杂签名定义为函数类型,以便于阅读。

 
   
   
 
  1. package main


  2. import "fmt"


  3. func test(fn func() int) int {

  4. return fn()

  5. }

  6. // 定义函数类型。

  7. type FormatFunc func(s string, x, y int) string


  8. func format(fn FormatFunc, s string, x, y int) string {

  9. return fn(s, x, y)

  10. }


  11. func main() {

  12. s1 := test(func() int { return 100 }) // 直接将匿名函数当参数。


  13. s2 := format(func(s string, x, y int) string {

  14. return fmt.Sprintf(s, x, y)

  15. }, "%d, %d", 10, 20)


  16. println(s1, s2)

  17. }

输出结果:

 
   
   
 
  1. 100 10, 20

有返回值的函数,必须有明确的终止语句,否则会引发编译错误。

你可能会偶尔遇到没有函数体的函数声明,这表示该函数不是以Go实现的。这样的声明定义了函数标识符。

 复制代码
 
   
   
 
  1. package math


  2. func Sin(x float64) float //implemented in assembly language


2. 参数

2.1.1. 函数参数

函数定义时指出,函数定义时有参数,该变量可称为函数的形参。形参就像定义在函数体内的局部变量。

但当调用函数,传递过来的变量就是函数的实参,函数可以通过两种方式来传递参数:

值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

 
   
   
 
  1. func swap(x, y int) int {

  2. ... ...

  3. }

 
   
   
 
  1. package main


  2. import (

  3. "fmt"

  4. )


  5. /* 定义相互交换值的函数 */

  6. func swap(x, y *int) {

  7. var temp int


  8. temp = *x /* 保存 x 的值 */

  9. *x = *y /* 将 y 值赋给 x */

  10. *y = temp /* 将 temp 值赋给 y*/


  11. }


  12. func main() {

  13. var a, b int = 1, 2

  14. /*

  15. 调用 swap() 函数

  16. */

  17. swap(&a, &b)


  18. fmt.Println(a, b)

  19. }

输出结果:

 
   
   
 
  1. 2 1

在默认情况下,Go 语言使用的是值传递,即在调用过程中不会影响到实际参数。

注意2:map、slice、chan、指针、interface默认以引用的方式传递。

不定参数传值 就是函数的参数不是固定的,后面的类型是固定的。(可变参数)

Golang 可变参数本质上就是 slice。只能有一个,且必须是最后一个。

在参数赋值时可以不用用一个一个的赋值,可以直接传递一个数组或者切片,特别注意的是在参数后加上“…”即可。

 
   
   
 
  1. func myfunc(args ...int) { //0个或多个参数

  2. }


  3. func add(a int, argsint) int { //1个或多个参数

  4. }


  5. func add(a int, b int, argsint) int { //2个或多个参数

  6. }

注意:其中args是一个slice,我们可以通过arg[index]依次访问所有参数,通过len(arg)来判断传递参数的个数.

任意类型的不定参数:就是函数的参数和每个参数的类型都不是固定的。

用interface{}传递任意类型数据是Go语言的惯例用法,而且interface{}是类型安全的。

 
   
   
 
  1. func myfunc(args ...interface{}) {

  2. }

代码:

 
   
   
 
  1. package main


  2. import (

  3. "fmt"

  4. )


  5. func test(s string, n ...int) string {

  6. var x int

  7. for _, i := range n {

  8. x += i

  9. }


  10. return fmt.Sprintf(s, x)

  11. }


  12. func main() {

  13. println(test("sum: %d", 1, 2, 3))

  14. }

输出结果:

 
   
   
 
  1. sum: 6

使用 slice 对象做变参时,必须展开。(slice…)

 复制代码
 
   
   
 
  1. package main


  2. import (

  3. "fmt"

  4. )


  5. func test(s string, n ...int) string {

  6. var x int

  7. for _, i := range n {

  8. x += i

  9. }


  10. return fmt.Sprintf(s, x)

  11. }


  12. func main() {

  13. s := []int{1, 2, 3}

  14. res := test("sum: %d", s...) // slice... 展开slice

  15. println(res)

  16. }

3. 返回值

3.1.1. 函数返回值

"_"标识符,用来忽略函数的某个返回值

Go 的返回值可以被命名,并且就像在函数体开头声明的变量那样使用。

返回值的名称应当具有一定的意义,可以作为文档使用。

没有参数的 return 语句返回各个返回变量的当前值。这种用法被称作“裸”返回。

直接返回语句仅应当用在像下面这样的短函数中。在长的函数中它们会影响代码的可读性。

 
   
   
 
  1. package main


  2. import (

  3. "fmt"

  4. )


  5. func add(a, b int) (c int) {

  6. c = a + b

  7. return

  8. }


  9. func calc(a, b int) (sum int, avg int) {

  10. sum = a + b

  11. avg = (a + b) / 2


  12. return

  13. }


  14. func main() {

  15. var a, b int = 1, 2

  16. c := add(a, b)

  17. sum, avg := calc(a, b)

  18. fmt.Println(a, b, c, sum, avg)

  19. }

输出结果:

 
   
   
 
  1. 1 2 3 3 1

Golang返回值不能用容器对象接收多返回值。只能用多个变量,或 "_" 忽略。

 
   
   
 
  1. package main


  2. func test() (int, int) {

  3. return 1, 2

  4. }


  5. func main() {

  6. // s := make([]int, 2)

  7. // s = test() // Error: multiple-value test() in single-value context


  8. x, _ := test()

  9. println(x)

  10. }

输出结果:

 
   
   
 
  1. 1

多返回值可直接作为其他函数调用实参。

 
   
   
 
  1. package main


  2. func test() (int, int) {

  3. return 1, 2

  4. }


  5. func add(x, y int) int {

  6. return x + y

  7. }


  8. func sum(n ...int) int {

  9. var x int

  10. for _, i := range n {

  11. x += i

  12. }


  13. return x

  14. }


  15. func main() {

  16. println(add(test()))

  17. println(sum(test()))

  18. }

输出结果:

 
   
   
 
  1. 3

  2. 3

命名返回参数可看做与形参类似的局部变量,最后由 return 隐式返回。

 
   
   
 
  1. package main


  2. func add(x, y int) (z int) {

  3. z = x + y

  4. return

  5. }


  6. func main() {

  7. println(add(1, 2))

  8. }

输出结果:

 
   
   
 
  1. 3

命名返回参数可被同名局部变量遮蔽,此时需要显式返回。

 
   
   
 
  1. func add(x, y int) (z int) {

  2. { // 不能在一个级别,引发 "z redeclared in this block" 错误。

  3. var z = x + y

  4. // return // Error: z is shadowed during return

  5. return z // 必须显式返回。

  6. }

  7. }

命名返回参数允许 defer 延迟调用通过闭包读取和修改。

 
   
   
 
  1. package main


  2. func add(x, y int) (z int) {

  3. defer func() {

  4. z += 100

  5. }()


  6. z = x + y

  7. return

  8. }


  9. func main() {

  10. println(add(1, 2))

  11. }

输出结果:

 
   
   
 
  1. 103

显式 return 返回前,会先修改命名返回参数。

 
   
   
 
  1. package main


  2. func add(x, y int) (z int) {

  3. defer func() {

  4. println(z) // 输出: 203

  5. }()


  6. z = x + y

  7. return z + 200 // 执行顺序: (z = z + 200) -> (call defer) -> (return)

  8. }


  9. func main() {

  10. println(add(1, 2)) // 输出: 203

  11. }

输出结果:

 复制代码
 
   
   
 
  1. 203

  2. 203


以上是关于Go语言之函数的主要内容,如果未能解决你的问题,请参考以下文章

Go语言设计模式之函数式选项模式

Go语言之Go语言 异常处理与测试

GO基础之函数

7.Go语言基础之函数

你知道的Go切片扩容机制可能是错的

go语言基础之init函数的介绍