2018年8月11日 星期六

go語言學習(11)--閉包與函數語言程式設計




文章摘要: return func(v int) int {閉包是將函式內部和函式外部連線起來的橋樑 go 閉包 func adder() func(int) int {


閉包


通過一個累加器來看閉包的概念


python 閉包


def fun1():
sum = 0
def fun2(v):
nonlocal sum
sum += v
return sum
return fun2

a = fun1()
for i in range(10):
print(a(i))

fun1返回的不是一個值,而是一個函式 fun2,a = fun2,所以 a(i)會列印 sum 的值,為什麼 sum 一直在加呢,函式裡的值為什麼可以帶到函式體外呢,這就是閉包的神奇之處,閉包是離散數學的一個概念,可以多看看網上的講解加深印象


其實可以把閉包看做一個類, sum 就是類裡的屬性, fun2就是類的方法



所以 fun2可以使用 sum(自由變數)


java 閉包


static Function adder() 
final Holder sum = new Holder(0);
return (Integer value) ->
sum.value += value;
return sum.value;
;


public static void main(String[] args)
Function a = adder();
for (int i = 0; i

java 裡函式不能像變數一樣傳遞,但也能模擬閉包這裏的 adder 其實是一個 Function 物件


上面 python 程式碼裡 sum 前有個 nonlocal 修飾,表明 sum 不是一個區域性變數,這裏直接用了 final 修飾


閉包就是能夠讀取其他函式內部變數的函式。例如在javascript中,只有函式內部的子函式才能讀取區域性變數,所以閉包可以理解成「定義在一個函式內部的函式「。在本質上,閉包是將函式內部和函式外部連線起來的橋樑


go 閉包


func adder() func(int) int 
sum := 0
return func(v int) int
sum += v
return sum


但是正統的函數語言程式設計不是這樣,函式其實是一個系統,我們只關心,入參(x)和返回值(y)是什麼,其實裏面是怎麼實現的我們並不關心,現代的很多業務程式碼,其實在函式體內做了很多事情,創造了很多變數和物件,這其實被稱為函式的"副作用"


還是看累加器


// 正統的函數語言程式設計
// 只有常量和函式
type iAdder func(int) (int, iAdder)

func adder2(base int) iAdder
return func(i int) (int, iAdder)
return base + i, adder2(base + i)



func main()
a := adder2(0)
for i := 0; i

函數語言程式設計入門


斐波那契數列



func fib() func() int 
a, b := 1, 1
return func() int
a, b = b, a+b
return a



f := fib()
for i := 0; i

這是用 print 列印的 fib 數,之前說道了 read 和 write 這兩個基本介面.


現在讓 fib這個函式實現一個 read 介面,然後任何能接收 reader 的方法都能輸出這個 fib 數了


// 定義一個函式的結構體,用函式實現介面,函式和普通變數一樣
type intGen func() int

func fib1() intGen
a, b := 1, 1
return func() int
a, b = b, a+b
return a


把滑鼠放到intGen 上,然後右鍵





image






image






image



func (g intGen) Read(p []byte) (n int, err error) 
// 下一個 fib 數
next := g()
//fib 數讀不完,需要有一個結束條件
if next > 1000
return 0, io.EOF

// 底層找一個已經實現的
s := fmt.Sprintf("%dn", next)
return strings.NewReader(s).Read(p)

註釋已經寫得很清楚了,讓 intGen 這個函式結構體實現 reader 介面,等會就可以寫一個 接收 reader 引數的print 函式,把intGen函式當做引數傳進去了



/**
列印的方法
讓 fib 實現 Reader 介面,就可以用 print 方法列印了
*/
func printFileContents(reader io.Reader)
scanner := bufio.NewScanner(reader)
for scanner.Scan()
fmt.Println(scanner.Text())



f1 := fib1()
printFileContents(f1)

// 1 2 3 5 8 13 21 34 ... 610 987

goimports


一個好用的工具





image



能夠自動整理imports


把沒用到的去除,用到的,但系統沒有的,自動 go get


但是正常是下不下來的,因為需要下載
golang.org/x/tools/cmd/goimports ,而
golang.org


在國內是被牆的


  1. go get -v github.com/gpmgo/gopm ,github 在國內沒被牆,先下載 gopm 這個工具

  2. 配置 $ GOPATH:bin

  3. gopm get -v -g -u golang.org/x/tools/cmd/goimportsgopm 下載谷歌的工具包

  4. go install golang.org/x/tools/cmd/goimportsgoimports 安裝到$ GOPATH 下

總結


scip


上述程式碼均已上傳至 github, 歡迎 star


https://github.com/yejunyu/golearn





image






http://www.buzzfunnews.com/20180826836.html

更多有趣新聞請上:http://www.buzzfunnews.com

沒有留言:

張貼留言