Golang的函數和閉包

多個參數

package main

import "fmt"

func add(x, y int) (ret int) {
 //x的類型省略,x和相鄰的y同類型,返回值指定爲ret int,如果返回值僅int,則可返回任意的int數據
	ret = x + y //ret直接使用,無須再定義
	return      //可以省略ret,不能省略return
}
func main() {
	ret := add(10, 20)
	fmt.Println(ret)
}

可變參數

package main

import "fmt"

//有一個整數參數x和一個可變參數nums,編寫函數實現x是否在nums中出現
func hasX(x int, nums ...int) bool {
	for _, v := range nums {
		if x == v {
			return true
		}
	}
	return false
}
func main() {
	has := hasX(10, 12, 34, 65, 78)
	if has {
		fmt.Println("x出現在nums切片中")
	} else {
		fmt.Println("x沒有出現在nums切片中")
	}
}

10會傳參給x,12, 34, 65, 78會以切片形式傳參給nums,在hasX函數體內可以將nums當作切片處理。

多個返回值

package main

import "fmt"

func addSub(x, y int) (int, int) {
	add := x + y
	sub := x - y
	return add, sub
}
func main() {
	ret1, ret2 := addSub(20, 10)
	fmt.Println(ret1, ret2)
}

addSub函數分別實現對傳入參數相加和相減操作,並且返回兩個結果,使用兩個變量接受返回值。當然也可以對多個返回值指定名稱,也可以如同省略參數類型一樣省略返回值類型。

package main

import "fmt"

func addSub(x, y int) (add, sub int) {
	add = x + y
	sub = x - y
	return
}
func main() {
	ret1, ret2 := addSub(20, 10)
	fmt.Println(ret1, ret2)
}

定義函數類型

我們可以使用type關鍵字來定義一個函數類型,具體格式如下:

type calculation func(int, int) int

上面語句定義了一個calculation類型,它是一種函數類型,這種函數接收兩個int類型的參數並且返回一個int類型的返回值。

簡單來說,凡是滿足這個條件的函數都是calculation類型的函數,例如下面的add和sub是calculation類型。

func add(x, y int) int {
	return x + y
}

func sub(x, y int) int {
	return x - y
}

add和sub都能賦值給calculation類型的變量。

var c calculation
c = add

被賦值的c變量,類型是main.calculation類型,c()等同於add()

package main

import "fmt"

type calculation func(int, int) int

func add(x, y int) int {
	return x + y
}

func sub(x, y int) int {
	return x - y
}
func main() {
	var fun1, fun2 calculation
	fun1, fun2 = add, sub
	ret1 := fun1(20, 10)
	ret2 := fun2(20, 10)
	fmt.Printf("fun1:%T\tfun2:%T\n", fun1, fun2)
	fmt.Println(ret1, ret2)
}

函數作爲參數

package main

import "fmt"

func add(x, y int) int {
	return x + y
}

func sum(x, y int, op func(int, int) int) (ret int) {
//sum函數共有x,y,op三個參數,op的類型是op func(int, int) int,sum函數的返回值是ret int
	ret = op(x, y)
	return
}
func main() {
	res := sum(10, 20, add)
	fmt.Println(res)
}

當然函數也可以作爲函數的返回值,如下匿名函數部分。

匿名函數

go語言也可以將函數看做是對象,先看看匿名函數作爲函數返回值

package main

import "fmt"

func bag() func() {
	return func() {
		fmt.Println("hello,world")
	}
}
func main() {
	fun := bag()
	fun()
}

如上,bag函數的返回值是一個匿名函數,定義fun變量接受這個匿名函數之後就可以調用它。

package main

import "fmt"

func bag() {
	func() {
		fmt.Println("hello,world")
	}()
}
func main() {
	bag()
}

如上,並不需要bag函數返回匿名函數,bag函數內需要立即調用,可直接在定義匿名函數體後加()進行立即執行。

當然,也可以寫成如下形式

package main

import "fmt"

func bag() {
	fun:=func() {
		fmt.Println("hello,world")
	}
	fun()
}
func main() {
	bag()
}

閉包

閉包=函數+引用函數外變量

func adder() func(int) int {
	var x int
	return func(y int) int {
		x += y
		return x
	}
}

上述adder中的匿名函數就是閉包,該匿名函數使用了其外部變量x。

package main

import "fmt"

func closebag(base int) (func(int) int, func(int) int) {
	add := func(x int) int {
		base += x
		return base
	}
	sub := func(y int) int {
		base -= y
		return base
	}
	return add, sub
}
func main() {
	fun1, fun2 := closebag(200)
	a := fun2(10)
	b := fun1(20)
	fmt.Println(a, b)
}

上述closebag函數中的兩個匿名函數分別使用了add、sub兩個變量來接受,並且返回了這兩個函數變量,在這兩個匿名函數中都使用了其函數外部變量base。因此這兩個匿名函數都屬於閉包。

package main

import (
	"fmt"
	"strings"
)
//檢查字符串name是否值由suff字符結尾,如果不是返回name+suff
func checkSuff(suff string) (func(string)string) {
//checkSuff的返回值是一個有string類型參數和string類型返回值的匿名函數
	return func(name string)string{
		if !strings.HasSuffix(name,suff){
			return name+suff
		}
		return name
	}
}

func main() {
	fun:=checkSuff(".doc")
	str:=fun("word")
	fmt.Println(str)
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章