日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > php教程 > Go起步:8、Go的函數(shù)

Go起步:8、Go的函數(shù)

來源:程序員人生   發(fā)布時間:2016-12-08 17:14:10 閱讀次數(shù):3435次

函數(shù)是基本的代碼塊,用于履行1個任務(wù),是構(gòu)成代碼履行的邏輯結(jié)構(gòu)。
在Go語言中,函數(shù)的基本組成為:關(guān)鍵字func、函數(shù)名、參數(shù)列表、返回值、函數(shù)體和返回語句。

函數(shù)定義

函數(shù)其實在之前已見過了,第1次履行hello world程序的main()其實就是1個函數(shù),而且是1個比較特殊的函數(shù)。每一個go程序都是從名為main的package包的main()函數(shù)開始履行包的概念不是這里的重點,以后做單獨說明。同時main()函數(shù)是無參數(shù),無返回值的。
Go函數(shù)的完成定義以下:

func function_name( [parameter list] ) [return_types] { 函數(shù)體 }

定義解析:
從Go的函數(shù)定義可以看出,Go的返回值是放在函數(shù)名和參數(shù)后面的,這點和C及Java的差別還是很多大的。

  • func:Go的函數(shù)聲明關(guān)鍵字,聲明1個函數(shù)。
  • function_name:函數(shù)名稱,函數(shù)名和參數(shù)列表1起構(gòu)成了函數(shù)簽名。
  • parameter list:參數(shù)列表,指定的是參數(shù)類型、順序、及參數(shù)個數(shù)。參數(shù)是可選的,即函數(shù)可以不包括參數(shù)。參數(shù)就像1個占位符,這是參數(shù)被稱為形參,當(dāng)函數(shù)被調(diào)用時,將具體的值傳遞給參數(shù),這個值被稱為實際參數(shù)。
  • return_types:返回類型,函數(shù)返回1列值。return_types 是該列值的數(shù)據(jù)類型。這里需要注意的是Go函數(shù)支持多返回值。有些功能不需要返回值,這類情況下 return_types 不是必須的。
  • 函數(shù)體:函數(shù)定義的代碼集合,表示函數(shù)完成的動作。

函數(shù)調(diào)用

Go的函數(shù)調(diào)用只要通過函數(shù)名然后向函數(shù)傳遞參數(shù),函數(shù)就會履行并返回值回來。就像之前調(diào)用Println()輸出信息1樣。
這里提1點,如果函數(shù)和調(diào)用不在同1個包(package)內(nèi),需要先通過import關(guān)鍵字將包引入–import “fmt”。函數(shù)Println()就屬于包fmt。
這里可能注意到Println()函數(shù)命名是首字母是大寫的。在Go語言中函數(shù)名字的大小寫不單單是風(fēng)格,更直接體現(xiàn)了該函數(shù)的可見性。這和其他語言對函數(shù)或方法的命名規(guī)定可能有很大不同,像Java就推薦是駝峰的寫法,C也不建議函數(shù)名首字母是大寫。但是在Go中,如果首字母不大寫,你可能會遇到稀里糊涂的編譯毛病, 比如你明明導(dǎo)入了對應(yīng)的包,Go編譯器還是會告知你沒法找到這個函數(shù)。
因此在Go中,需要記住1個規(guī)則:

小寫字母開頭的函數(shù)只在本包內(nèi)可見,大寫字母開頭的函數(shù)才能被其他包使用。

同時這個規(guī)則也適用于變量的可見性,即首字母大寫的變量才是全局的。

package main import "fmt" /* 函數(shù)返回兩個數(shù)的較大值 */ func max(num1 int, num2 int) int { /* 定義局部變量 */ var result int if num1 > num2 { result = num1 } else { result = num2 } return result } func main() { var a int = 100 var b int = 200 var ret int /* 調(diào)用函數(shù)并返回較大值 */ ret = max(a, b) fmt.Printf("最大值是 : %d\n", ret) }

這里寫圖片描述
上面定義了1個函數(shù)max(),用于比較兩個數(shù),并返回其中較大的1個。終究通過main() 函數(shù)中調(diào)用 max()函數(shù)履行。
這里關(guān)于函數(shù)的參數(shù)列表有1個簡便寫法,當(dāng)連續(xù)兩個或多個函數(shù)的已命名形參類型相同時,除最后1個類型之外,其它都可以省略。
就像上面的func max(num1 int, num2 int) int {}定義,可以簡寫成

func max(num1 , num2 int) int {}

多返回值

前面定義函數(shù)時說過,Go的函數(shù)支持多返回值,這與C、C++和Java等開發(fā)語言極大不同。這個特性能夠使我們寫出比其他語言更優(yōu)雅、更簡潔的代碼,比如File.Read()函 數(shù)就能夠同時返回讀取的字節(jié)數(shù)和毛病信息。如果讀取文件成功,則返回值中的n為讀取的字節(jié) 數(shù),err為nil,否則err為具體的出錯信息:

func (file *File) Read(b []byte) (n int, err Error)

1個簡單的例子以下:

package main import "fmt" func swap(x, y string) (string, string) { return y, x } func main() { a, b := swap("hello", "world") fmt.Println(a, b) }

這里寫圖片描述
上面實現(xiàn)了簡單的字符串交換功能,代碼實現(xiàn)上10分的簡潔,由于支持多返回值,所以不需要想Java需要構(gòu)建1個可以保存多個值得數(shù)據(jù)結(jié)構(gòu)。
而且可以發(fā)現(xiàn),對返回值如果是同1類型,可以不定義變量名稱,雖然代碼看上去是簡潔了很多,但是命名后的返回值可讓代碼更清晰,可讀性更強(qiáng)。

如果調(diào)用方調(diào)用了1個具有多返回值的方法,但是卻不想關(guān)心其中的某個返回值,可以簡單 地用1個下劃線“_”來跳過這個返回值。就像上面的例子,如果我們只關(guān)注第1個返回值則可以寫成:

a, _ := swap("hello", "world")

若值關(guān)注第2返回值則可以寫成:

_, b := swap("hello", "world")

函數(shù)參數(shù)

函數(shù)定義時指出,函數(shù)定義時有參數(shù),該變量可稱為函數(shù)的形參。形參就像定義在函數(shù)體內(nèi)的局部變量。
但當(dāng)調(diào)用函數(shù),傳遞過來的變量就是函數(shù)的實參,函數(shù)可以通過兩種方式來傳遞參數(shù):

  1. 值傳遞:指在調(diào)用函數(shù)時將實際參數(shù)復(fù)制1份傳遞到函數(shù)中,這樣在函數(shù)中如果對參數(shù)進(jìn)行修改,將不會影響到實際參數(shù)。
  2. 援用傳遞:是指在調(diào)用函數(shù)時將實際參數(shù)的地址傳遞到函數(shù)中,那末在函數(shù)中對參數(shù)所進(jìn)行的修改,將影響到實際參數(shù)。

在默許情況下,Go 語言使用的是值傳遞,即在調(diào)用進(jìn)程中不會影響到實際參數(shù)。

值傳遞

Go中int類型保存的的是1個數(shù)字類型,下面定義1個交換函數(shù)swap(),用于交換兩個參數(shù)的值。

package main import "fmt" func main() { var a int = 100 var b int = 200 fmt.Printf("交換前 a 的值為 : %d\n", a) fmt.Printf("交換前 b 的值為 : %d\n", b) /* 通過調(diào)用函數(shù)來交換值 */ swap(a, b) fmt.Printf("交換后 a 的值 : %d\n", a) fmt.Printf("交換后 b 的值 : %d\n", b) } /* 定義相互交換值的函數(shù) */ func swap(x, y int) int { var temp int temp = x /* 保存 x 的值 */ x = y /* 將 y 值賦給 x */ y = temp /* 將 temp 值賦給 y*/ return temp }

這里寫圖片描述

援用參數(shù)

通過前面的介紹可以知道,Go的指針類型是對變量地址的援用。
將上面的swap()做些修改,參數(shù)接受兩個指針類型,然后做交換。

package main import "fmt" func main() { var a int = 100 var b int = 200 fmt.Printf("交換前 a 的值為 : %d\n", a) fmt.Printf("交換前 b 的值為 : %d\n", b) /* 調(diào)用 swap() 函數(shù) * &a 指向 a 指針,a 變量的地址 * &b 指向 b 指針,b 變量的地址 */ swap(&a, &b) fmt.Printf("交換后 a 的值 : %d\n", a) fmt.Printf("交換后 b 的值 : %d\n", b) } /* 定義相互交換值的函數(shù) */ func swap(x, y *int) { var temp int temp = *x /* 保存 x 的值 */ *x = *y /* 將 y 值賦給 x */ *y = temp /* 將 temp 值賦給 y*/ }

這里寫圖片描述
可以發(fā)現(xiàn),終究傳進(jìn)來的參數(shù)指在履行交換函數(shù)swap()后也被修改了,這是由于參數(shù)終究指向的都是地址的援用,所有援用被修改了,值也就相應(yīng)的變了。

不定參數(shù)

顧名思義,不定參數(shù)就是函數(shù)的參數(shù)不是固定的。這個在C和Java里都有。在之前的代碼中,包fmt下面的 fmt.Println()函數(shù)也是參數(shù)不定的。

不定參數(shù)類型

先看1個函數(shù)的定義:

func myfunc(args ...int) { }

可以看出,上面的定義和之前的函數(shù)定義最大的不同就是,他的參數(shù)是以“…type”的方式定義的,這和Java的語法有些類似,也是用”…”實現(xiàn)。需要說明的是“…type”在Go中只能作為參數(shù)的情勢出現(xiàn),而且只能作為函數(shù)的最后1個參數(shù)。
從內(nèi)部實現(xiàn)機(jī)理上來講,類型“…type“本質(zhì)上是1個數(shù)組切片,也就是[]type,這點可以從下面的1個小程序驗證1下。

package main import "fmt" func main() { var a int = 100 var b int = 200 myfunc(a, b) } func myfunc(args ...int) { fmt.Println(args) for _, arg := range args { fmt.Println(arg) } }

這里寫圖片描述
從上面的結(jié)果可以看出,類型“…type“本質(zhì)上是1個數(shù)組切片,也就是[]type,所以參數(shù)args可以用for循環(huán)來取得每一個傳入的參數(shù)。
這是Go的1 個語法糖(syntactic sugar),即這類語法對語言的功能并沒有影響,但是更方便程序員使用。通常來講,使用語法糖能夠增加程序的可讀性,從而減少程序出錯的機(jī)會。

不定參數(shù)的傳遞

一樣是上面的myfunc(args …int)函數(shù)為例,在參數(shù)賦值時可以不用用1個1個的賦值,可以直接傳遞1個數(shù)組或切片,特別注意的是在參數(shù)后加上“…”便可。

package main import "fmt" func main() { arr := []int{100, 200, 300} myfunc(arr...) myfunc(arr[:2]...) } func myfunc(args ...int) { fmt.Println(args) for _, arg := range args { fmt.Println(arg) } }

這里寫圖片描述

任意類型的不定參數(shù)

上面的例子在定義不定參數(shù)時,都有1個要求,參數(shù)的類型是1致的。那末如果函數(shù)的參數(shù)類型不1致,如何使用不定參數(shù)方式來定義。在Go中,要實現(xiàn)這個需求需要引入1個新的類型–interface{}。看名字可以看出,這類類型實際上就是接口。關(guān)于Go的接口這里只做引出。
看1下之前經(jīng)常使用的Printf函數(shù)的定義,位置在Go的src目錄下的print.go文件中。

func Println(a ...interface{}) (n int, err error) { return Fprintln(os.Stdout, a...) }

其實用interface{}傳遞任意類型數(shù)據(jù)是Go語言的慣例用法,而且interface{}是類型安全的。
看下面的例子:

package main import ( "fmt" "reflect" ) func main() { arr := []int{100, 200, 300} myfunc(100, "abc", arr) } func myfunc(args ...interface{}) { fmt.Println(args) for _, arg := range args { fmt.Println(arg) fmt.Println(reflect.TypeOf(arg)) fmt.Println("=======") } }

這里寫圖片描述

匿名函數(shù)

匿名函數(shù)是指不需要定義函數(shù)名的1種函數(shù)實現(xiàn)方式。1958年LISP首先采取匿名函數(shù)。
在Go里面,函數(shù)可以像普通變量1樣被傳遞或使用,Go語言支持隨時在代碼里定義匿名函數(shù)。
匿名函數(shù)由1個不帶函數(shù)名的函數(shù)聲明和函數(shù)體組成。匿名函數(shù)的優(yōu)越性在于可以直接使用函數(shù)內(nèi)的變量,沒必要申明。
直接看1個例子:

package main import ( "fmt" "math" ) func main() { getSqrt := func(a float64) float64 { return math.Sqrt(a) } fmt.Println(getSqrt(4)) }

這里寫圖片描述
上面先定義了1個名為getSqrt 的變量,初始化該變量時和之前的變量初始化有些不同,使用了func,func是定義函數(shù)的,可是這個函數(shù)和上面說的函數(shù)最大不同就是沒有函數(shù)名,也就是匿名函數(shù)。這里將1個函數(shù)當(dāng)作1個變量1樣的操作。

閉包

理解閉包

閉包的應(yīng)當(dāng)都聽過,但到底甚么是閉包呢?
閉包是由函數(shù)及其相干援用環(huán)境組合而成的實體(即:閉包=函數(shù)+援用環(huán)境)。
“官方”的解釋是:所謂“閉包”,指的是1個具有許多變量和綁定了這些變量的環(huán)境的表達(dá)式(通常是1個函數(shù)),因此這些變量也是該表達(dá)式的1部份。
維基百科講,閉包(Closure),是援用了自由變量的函數(shù)。這個被援用的自由變量將和這個函數(shù)1同存在,即便已離開了創(chuàng)造它的環(huán)境也不例外。所以,有另外一種說法認(rèn)為閉包是由函數(shù)和與其相干的援用環(huán)境組合而成的實體。閉包在運行時可以有多個實例,不同的援用環(huán)境和相同的函數(shù)組合可以產(chǎn)生不同的實例。
看著上面的描寫,會發(fā)現(xiàn)閉包和匿名函數(shù)仿佛有些像。可是可能還是有些云里霧里的。由于跳過閉包的創(chuàng)建進(jìn)程直接理解閉包的定義是非常困難的。目前在JavaScript、Go、PHP、Scala、Scheme、Common Lisp、Smalltalk、Groovy、Ruby、 Python、Lua、objective c、swift 和Java8以上等語言中都能找到對閉包不同程度的支持。通過支持閉包的語法可以發(fā)現(xiàn)1個特點,他們都有垃圾回收(GC)機(jī)制。
JavaScript應(yīng)當(dāng)是普及度比較高的編程語言了,通過這個來舉例應(yīng)當(dāng)好理解寫。看下面的代碼,只要關(guān)注script里方法的定義和調(diào)用就能夠了。

<!DOCTYPE html> <html lang="zh"> <head> <title></title> </head> <body> </body> </html> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script> <script> function a(){ var i=0; function b(){ console.log(++i); document.write("<h1>"+i+"</h1>"); } return b; } $(function(){ var c=a(); c(); c(); c(); //a(); //不會有信息輸出 document.write("<h1>=============</h1>"); var c2=a(); c2(); c2(); }); </script>

這里寫圖片描述
這段代碼有兩個特點:

  1. 函數(shù)b嵌套在函數(shù)a內(nèi)部
  2. 函數(shù)a返回函數(shù)b

這樣在履行完var c=a()后,變量c實際上是指向了函數(shù)b(),再履行函數(shù)c()后就會顯示i的值,第1次為1,第2次為2,第3次為3,以此類推。
其實,這段代碼就創(chuàng)建了1個閉包。由于函數(shù)a()外的變量c援用了函數(shù)a()內(nèi)的函數(shù)b(),就是說:

當(dāng)函數(shù)a()的內(nèi)部函數(shù)b()被函數(shù)a()外的1個變量援用的時候,就創(chuàng)建了1個閉包

在上面的例子中,由于閉包的存在使得函數(shù)a()返回后,a中的i始終存在,這樣每次履行c(),i都是自加1后的值。
從上面可以看出閉包的作用就是在a()履行完并返回后,閉包使得Javascript的垃圾回收機(jī)制GC不會收回a()所占用的資源,由于a()的內(nèi)部函數(shù)b()的履行需要依賴a()中的變量i。

在給定函數(shù)被屢次調(diào)用的進(jìn)程中,這些私有變量能夠保持其持久性。變量的作用域僅限于包括它們的函數(shù),因此沒法從其它程序代碼部份進(jìn)行訪問。不過,變量的生存期是可以很長,在1次函數(shù)調(diào)用期間所創(chuàng)建所生成的值在下次函數(shù)調(diào)用時依然存在。正由于這1特點,閉包可以用來完成信息隱藏,并進(jìn)而利用于需要狀態(tài)表達(dá)的某些編程范型中。

下面來想象另外一種情況,如果a()返回的不是函數(shù)b(),情況就完全不同了。由于a()履行完后,b()沒有被返回給a()的外界,只是被a()所援用,而此時a()也只會被b()引 用,因此函數(shù)a()和b()相互援用但又不被外界打擾(被外界援用),函數(shù)a和b就會被GC回收。所以直接調(diào)用a();是頁面并沒有信息輸出。

下面來講閉包的另外一要素援用環(huán)境。c()跟c2()援用的是不同的環(huán)境,在調(diào)用i++時修改的不是同1個i,因此兩次的輸出都是1。函數(shù)a()每進(jìn)入1次,就構(gòu)成了1個新的環(huán)境,對應(yīng)的閉包中,函數(shù)都是同1個函數(shù),環(huán)境卻是援用不同的環(huán)境。這和c()和c()的調(diào)用順序都是無關(guān)的。

以上就是對閉包作用的非常直白的描寫,不專業(yè)也不嚴(yán)謹(jǐn),但大概意思就是這樣,理解閉包需要按部就班的進(jìn)程。

Go的閉包

Go語言是支持閉包的,這里只是簡單地講1下在Go語言中閉包是如何實現(xiàn)的。
下面我來將之前的JavaScript的閉包例子用Go來實現(xiàn)。

package main import ( "fmt" ) func a() func() int { i := 0 b := func() int { i++ fmt.Println(i) return i } return b } func main() { c := a() c() c() c() //a() //不會輸出i }

這里寫圖片描述
可以發(fā)現(xiàn),輸出和之前的JavaScript的代碼是1致的。具體的緣由和上面的也是1樣的,這里就不在贅述了。
這頁說明Go語言是支持閉包的,至于具體是如何支持的目前就先做討論了。

關(guān)于閉包這里也只講到了基本的概念,至于更深入的東西我目前能力有限只能靠以后漸漸摸索。就像上面講到的,理解閉包需要按部就班的進(jìn)程。

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 91骚视频| 最近中文字幕在线 | 国产 一区 | 国产精品视频久久久 | 国产小视频在线播放 | 日韩毛片免费视频一级特黄 | 国产成人免费视频 | 57pao国产精品一区 | 久久精品国产一区二区三区 | 国产精选视频在线观看 | 久久久久黄色 | 亚洲久久网 | 偷拍自拍网 | 美日韩av | 美女黄18 | 亚洲欧美不卡 | 99久久久无码国产精品 | 国产成人a亚洲精品 | 国产精品乱码一区二区三区 | 久草视频免费 | 日本一区不卡视频 | 视频一区二区在线 | 久久成人综合 | 日日操夜夜操狠狠操 | 国产成人精品网站 | 午夜久久久久久久久 | 黄色不卡| 免费黄色三级 | 中文字幕在线观看日韩 | 狼人综合在线 | 国产精品日本一区二区不卡视频 | 亚洲在线免费观看 | 中文精品视频 | 国产精品麻豆视频 | 国产精品久久久久一区二区三区 | 成人国产综合 | 亚洲视频观看 | 欧美激情网址 | 亚洲精品一区二区三区中文字幕 | 欧美日韩三区 | 久久久免费 |