GO开发[四]:golang函数

函数

1.声明语法:func 函数名 (参数列表) [(返回值列表)] {}

2.golang函数特点:

a. 不支持重载,一个包不能有两个名字一样的函数

b. 函数是一等公民,函数也是一种类型,一个函数可以赋值给变量

c. 匿名函数

d. 多返回值

定义函数类型type:

package main

import "fmt"

type add_func func(int, int) int

func add(a, b int) int {
   return a + b
}

func sub(a, b int) int {
   return a - b
}

func operator(op add_func, a int, b int) int {
   return op(a, b)
}

func main() {
   c := add
   fmt.Println(c)
   sum := operator(c, 100, 200)
   fmt.Println(sum)

   var x add_func
   x=sub
   fmt.Println(x)
   sub := operator(x, 100, 200)
   fmt.Println(sub)
   
}

3.函数参数传递方式:

1). 值传递

2). 引用传递

注意1:无论是值传递,还是引用传递,传递给函数的都是变量的副本,不过,值传递是值的拷贝。

引用传递是地址的拷贝,一般来说,地址拷贝更为高效。而值拷贝取决于拷贝的对象大小,对象越大,则性能越低。

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

package main

import "fmt"

func modify(a *int) {
   *a = 100
}

func main() {
   a := 8
   fmt.Println(a)
   modify(&a)
   fmt.Println(a)
}

参数类型省略:

func f(i, j, k int, s, t string)
func f(i int, j int, k int, s string, t string)

4.命名返回值的名字:

package main
import "fmt"
func split(sum int) (x, y int) {
	x = sum / 10
	y = sum % 10
	return
} 
func main() {
	fmt.Println(split(17))
}

_标识符,用来忽略返回值

5.可变参数:

func add(arg …int) int {
}//0个或多个参数
func add(a int, arg …int) int {
}//1个或多个参数
func add(a int, b int, arg …int) int {
}//2个或多个参数

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

练习:写一个函数add,支持1个或多个int相加,并返回相加结果

练习:写一个函数concat,支持1个或多个string相拼接,并返回结果

defer

1.当函数返回时,执行defer语句。可以用来做资源清理

2.多个defer语句,按先进后出的方式执行,即最后一个defer语句将最先被执行

3.defer语句中的变量,在defer声明时就决定了。

在函数将要返回前执行:

package main

import "fmt"

func print() {
   defer func() {
      fmt.Println("defer")
   }()
   fmt.Println("hello")
}

func main()  {
   print()
}

多个defer语句:

package main

import "fmt"

func main()  {
   var i int =1
   fmt.Println(i)
   defer fmt.Println(i)
   //不会立即执行,压到栈里面,函数执行结束后,再执行栈里的
   defer fmt.Println("a")
   i=10
   fmt.Println(i)
}

用途:

1.关闭文件句柄

2.锁资源释放

3.数据库连接释放

内置函数

1.close:主要用来关闭channel

2.len:用来求长度,比如string、array、slice、map、channel

3.new:用来分配内存,主要用来分配值类型,比如int、struct。返回的是指针

package main

import "fmt"

func main()  {
   var i int
   fmt.Println(i)

   j := new(int)
   fmt.Println(j)
   fmt.Println(*j)

   *j = 100
   fmt.Println(*j)
}

4.make:用来分配内存,主要用来分配引用类型,比如chan、map、slice

new和make的区别:

package main

import "fmt"

func test() {
   s1 := new([]int)
   fmt.Println(s1)

   s2 := make([]int, 10)
   fmt.Println(s2)

   *s1 = make([]int, 5)
   (*s1)[0] = 100
   s2[0] = 100
   fmt.Println(s1)
   fmt.Println(s2)
   return
}

func main() {
   test()
}

5.append:用来追加元素到数组、slice中

package main

import "fmt"

func main()  {
   var a []int
   a = append(a,10,20,30)
   a = append(a,a...)
   fmt.Println(a)
}

错误处理error

Go语言引入了一个关于错误处理的标准模式,即error接口,该接口的定义如下:

type error interface {
	Error() string
}

1.初始化失败,退出

2.重试,比如if err !=nil,重试3次

3.异常上抛

package main

import "fmt"

func print() {
   var p *int
   fmt.Println(*p)
}

func main() {

   defer func() {
      err := recover()
      fmt.Println(err)
   }()
   panic("不想执行下去了")


   //print()//1.空指针引用错误


   //var n int
   //fmt.Println(10 / n) //2.除数为0

   /*
   var i=3
   var slice [3]int
   fmt.Println(slice[i])//3.下标越界
   */
}

EOF error

recover.go:

Go语言引入了两个内置函数panic()和recover()以报告和处理运行时错误和程序中的错误场景:

当在一个函数执行过程中调用panic()函数时,正常的函数执行流程将立即终止,但函数中之前使用defer关键字延迟执行的语句将正常展开执行,之后该函数将返回到调用函数,并导致逐层向上执行panic流程,直至所属的goroutine中所有正在执行的函数被终止。错误信息将被报告,包括在调用panic()函数时传入的参数,这个过程称为错误处理流程。

recover()函数用于终止错误处理流程。一般情况下, recover()应该在一个使用defer关键字的函数中执行以有效截取错误处理流程。如果没有在发生异常的goroutine中明确调用恢复过程(使用recover关键字) ,会导致该goroutine所属的进程打印异常信息后直接退出。

package main

import (
   "fmt"
   "time"
)

func test() {
   defer func() {
      if err := recover(); err != nil {
         fmt.Println(err)
      }
   }()

   b:=0
   a := 1/b
   fmt.Println(a)
   return
}

func main() {
   for {
      test()
      time.Sleep(time.Second)
   }
}

panic.go

package main

import (
   "fmt"
   "time"
   "errors"
)
func initConfig() (err error) {
   return errors.New("init config failed")
}
   err := initConfig()
   if err != nil {
      panic(err)
   }
   return
}

func main() {
   for {
      test()
      time.Sleep(time.Second)
   }
}

递归

一个函数调用自己,就叫做递归。

package main

import (
   "fmt"
   "time"
)

func recusive(n int) {
   fmt.Println("hello golang", n)
   time.Sleep(time.Second)
   if n > 10 {
      return
   }
   recusive(n + 1)
}

func main() {
   recusive(0)
}

递归实现阶乘和斐波那契数列:

package main

import (
   "fmt"
   "time"
)

func factor(n int) int {
   if n == 1 {
      return 1
   }
   return factor(n-1) * n
}

func fab(n int) int {
   if n <= 1 {
      return 1
   }
   return fab(n-1) + fab(n-2)
}

func main() {
   fmt.Println(factor(5))
   for i := 0; i < 10; i++ {
      fmt.Println(fab(i))
   }
}

函数类型

package main

import "fmt"

func print1(){
   fmt.Println("print1")
}

func print2() {
   fmt.Println("print2")
}

func func1(n int) int {
   return n+1
}

func main() {
   //变量是个筐,装这个变量类型的数据
   //函数也是个筐,容器,装的函数
   var f func()
   f = print1
   f()
   f=print2
   f()


   var flist [3]func(int) int
   flist[0]=func1
   m:=flist[0](10)
   fmt.Println(m)
   fmt.Println(flist[0](10))
}

加减乘除:

package main

import (
   "fmt"
   "os"
   "strconv"
)

func add(m, n int) int {
   return m + n
}

func sub(m, n int) int {
   return m - n
}

func comp(m,n int) int {
   return m * n
}

func div(m,n int) int {
   return m/n
}

func main() {
   funcmap := map[string]func(int, int) int{
      "+": add,
      "-": sub,
      "*":comp,
      "/":div,
   }

   m, _ := strconv.Atoi(os.Args[1])
   n, _ := strconv.Atoi(os.Args[3])

   f := funcmap[os.Args[2]]
   if f != nil {
      fmt.Println(f(m, n))
      }
}

匿名函数

匿名函数是指不需要定义函数名的一种函数实现方式

在Go里面,函数可以像普通变量一样被传递或使用,这与C语言的回调函数比较类似。不同的是, Go语言支持随时在代码里定义匿名函数。

package main
import (
	"fmt"
	"strings"
)
func toupper(s string) string {
	return strings.Map(func(r rune) rune {
		return r - ('a' - 'A')
	}, s)
}


func main() {
	f := func(x,y int) int {
		return x + y
	}
	fmt.Println(f(1,2))

	f1:=func(x,y int) int {
		return x + y
	}(1,3)
	fmt.Println(f1)
	
	fmt.Println(toupper("hello"))
}

闭包

闭包:一个函数和与其相关的引用环境组合而成的实体

package main

import (
   "fmt"
)

func addn(n int) func(int) int {
   return func(m int) int {
      return m+n
   }
}

func main() {
   f := addn(3)
   fmt.Println(f(12))
}

生成器:

package main

import "fmt"

func iter(s []int) func() int {
   var i = 0
   return func() int {
      if i >= len(s) {
         return 0
      }
      n := s[i]
      i += 1
      return n
   }
}

func main() {
   f := iter([]int{1, 2, 3})
   fmt.Println(f())
   fmt.Println(f())
   fmt.Println(f())
}
posted @ 2018-01-22 21:34  ninxin18  阅读(408)  评论(0编辑  收藏  举报