GO是編譯性語言,所以函數(shù)的順序是無關(guān)緊要的,為了方便閱讀,建議入口函數(shù) main 寫在最前面,其余函數(shù)按照功能需要進(jìn)行排列
西和網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)公司等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)公司2013年成立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
GO的函數(shù) 不支持嵌套,重載和默認(rèn)參數(shù)
GO的函數(shù) 支持 無需聲明變量,可變長度,多返回值,匿名,閉包等
GO的函數(shù)用 func 來聲明,且左大括號 { 不能另起一行
一個簡單的示例:
輸出為:
參數(shù):可以傳0個或多個值來供自己用
返回:通過用 return 來進(jìn)行返回
輸出為:
上面就是一個典型的多參數(shù)傳遞與多返回值
對例子的說明:
按值傳遞:是對某個變量進(jìn)行復(fù)制,不能更改原變量的值
引用傳遞:相當(dāng)于按指針傳遞,可以同時改變原來的值,并且消耗的內(nèi)存會更少,只有4或8個字節(jié)的消耗
在上例中,返回值 (d int, e int, f int) { 是進(jìn)行了命名,如果不想命名可以寫成 (int,int,int){ ,返回的結(jié)果都是一樣的,但要注意:
當(dāng)返回了多個值,我們某些變量不想要,或?qū)嶋H用不到,我們可以使用 _ 來補位,例如上例的返回我們可以寫成 d,_,f := test(a,b,c) ,我們不想要中間的返回值,可以以這種形式來舍棄掉
在參數(shù)后面以 變量 ... type 這種形式的,我們就要以判斷出這是一個可變長度的參數(shù)
輸出為:
在上例中, strs ...string 中, strs 的實際值是b,c,d,e,這就是一個最簡單的傳遞可變長度的參數(shù)的例子,更多一些演變的形式,都非常類似
在GO中 defer 關(guān)鍵字非常重要,相當(dāng)于面相對像中的析構(gòu)函數(shù),也就是在某個函數(shù)執(zhí)行完成后,GO會自動這個;
如果在多層循環(huán)中函數(shù)里,都定義了 defer ,那么它的執(zhí)行順序是先進(jìn)后出;
當(dāng)某個函數(shù)出現(xiàn)嚴(yán)重錯誤時, defer 也會被調(diào)用
輸出為
這是一個最簡單的測試了,當(dāng)然還有更復(fù)雜的調(diào)用,比如調(diào)試程序時,判斷是哪個函數(shù)出了問題,完全可以根據(jù) defer 打印出來的內(nèi)容來進(jìn)行判斷,非??焖?,這種留給你們?nèi)崿F(xiàn)
一個函數(shù)在函數(shù)體內(nèi)自己調(diào)用自己我們稱之為遞歸函數(shù),在做遞歸調(diào)用時,經(jīng)常會將內(nèi)存給占滿,這是非常要注意的,常用的比如,快速排序就是用的遞歸調(diào)用
本篇重點介紹了GO函數(shù)(func)的聲明與使用,下一篇將介紹GO的結(jié)構(gòu) struct
操作字符串離不開字符串的拼接,但是Go中string是只讀類型,大量字符串的拼接會造成性能問題。
拼接字符串,無外乎四種方式,采用“+”,“fmt.Sprintf()”,"bytes.Buffer","strings.Builder"
上面我們創(chuàng)建10萬字符串拼接的測試,可以發(fā)現(xiàn)"bytes.Buffer","strings.Builder"的性能最好,約是“+”的1000倍級別。
這是由于string是不可修改的,所以在使用“+”進(jìn)行拼接字符串,每次都會產(chǎn)生申請空間,拼接,復(fù)制等操作,數(shù)據(jù)量大的情況下非常消耗資源和性能。而采用Buffer等方式,都是預(yù)先計算拼接字符串?dāng)?shù)組的總長度(如果可以知道長度),申請空間,底層是slice數(shù)組,可以以append的形式向后進(jìn)行追加。最后在轉(zhuǎn)換為字符串。這申請了不斷申請空間的操作,也減少了空間的使用和拷貝的次數(shù),自然性能也高不少。
bytes.buffer是一個緩沖byte類型的緩沖器存放著都是byte
是一個變長的 buffer,具有 Read 和Write 方法。 Buffer 的 零值 是一個 空的 buffer,但是可以使用,底層就是一個 []byte, 字節(jié)切片。
向Buffer中寫數(shù)據(jù),可以看出Buffer中有個Grow函數(shù)用于對切片進(jìn)行擴容。
從Buffer中讀取數(shù)據(jù)
strings.Builder的方法和bytes.Buffer的方法的命名幾乎一致。
但實現(xiàn)并不一致,Builder的Write方法直接將字符拼接slice數(shù)組后。
其沒有提供read方法,但提供了strings.Reader方式
Reader 結(jié)構(gòu):
Buffer:
Builder:
可以看出Buffer和Builder底層都是采用[]byte數(shù)組進(jìn)行裝載數(shù)據(jù)。
先來說說Buffer:
創(chuàng)建好Buffer是一個empty的,off 用于指向讀寫的尾部。
在寫的時候,先判斷當(dāng)前寫入字符串長度是否大于Buffer的容量,如果大于就調(diào)用grow進(jìn)行擴容,擴容申請的長度為當(dāng)前寫入字符串的長度。如果當(dāng)前寫入字符串長度小于最小字節(jié)長度64,直接創(chuàng)建64長度的[]byte數(shù)組。如果申請的長度小于二分之一總?cè)萘繙p去當(dāng)前字符總長度,說明存在很大一部分被使用但已讀,可以將未讀的數(shù)據(jù)滑動到數(shù)組頭。如果容量不足,擴展2*c + n 。
其String()方法就是將字節(jié)數(shù)組強轉(zhuǎn)為string
Builder是如何實現(xiàn)的。
Builder采用append的方式向字節(jié)數(shù)組后添加字符串。
從上面可以看出,[]byte的內(nèi)存大小也是以倍數(shù)進(jìn)行申請的,初始大小為 0,第一次為大于當(dāng)前申請的最大 2 的指數(shù),不夠進(jìn)行翻倍.
可以看出如果舊容量小于1024進(jìn)行翻倍,否則擴展四分之一。(2048 byte 后,申請策略的調(diào)整)。
其次String()方法與Buffer的string方法也有明顯區(qū)別。Buffer的string是一種強轉(zhuǎn),我們知道在強轉(zhuǎn)的時候是需要進(jìn)行申請空間,并拷貝的。而Builder只是指針的轉(zhuǎn)換。
這里我們解析一下 *(*string)(unsafe.Pointer(b.buf)) 這個語句的意思。
先來了解下unsafe.Pointer 的用法。
也就是說,unsafe.Pointer 可以轉(zhuǎn)換為任意類型,那么意味著,通過unsafe.Pointer媒介,程序繞過類型系統(tǒng),進(jìn)行地址轉(zhuǎn)換而不是拷貝。
即*A = Pointer = *B
就像上面例子一樣,將字節(jié)數(shù)組轉(zhuǎn)為unsafe.Pointer類型,再轉(zhuǎn)為string類型,s和b中內(nèi)容一樣,修改b,s也變了,說明b和s是同一個地址。但是對s重新賦值后,意味著s的地址指向了“WORLD”,它們所使用的內(nèi)存空間不同了,所以s改變后,b并不會改變。
所以他們的區(qū)別就在于 bytes.Buffer 是重新申請了一塊空間,存放生成的string變量, 而strings.Builder直接將底層的[]byte轉(zhuǎn)換成了string類型返回了回來,去掉了申請空間的操作。
首先說一下go中的字符串類型:
字符串就是一串固定長度的字符連接起來的字符序列。Go的字符串是由單個字節(jié)連接起來的。Go語言的字符串的字節(jié)使用UTF-8編碼標(biāo)識Unicode文本。
下面介紹字符串的三種遍歷方式,根據(jù)實際情況選擇即可。
該遍歷方式==缺點==:遍歷是按照字節(jié)遍歷,因此如果有中文等非英文字符,就會出現(xiàn)亂碼,比如要遍歷"abc北京"這個字符串,效果如下:
可見這不是我們想要的效果,根據(jù)utf-8中文編碼規(guī)則,我們要str[3]str[4]str[5]三個字節(jié)合起來組成“北”字及 str[6]str[7]str[8]合起來組成“京”字。由此引出下面第二種遍歷方法。
該方式是按照字符遍歷的,所以不會出現(xiàn)亂碼,如下:
運行結(jié)果:
從圖中可以看到第二個漢子“京”的開始下標(biāo)是6,直接跳過了4和5,可見確實依照utf8編碼方式將三個字節(jié)組合成了一個漢字,str[3]-str[5]組合成“北”字,str[6]-str[8]組合成了“京”字。
由于下標(biāo)的不確定性,所以引出了下面的遍歷方式。
1 可以先將字符串轉(zhuǎn)成 []rune 切片
2 再用常規(guī)方法進(jìn)行遍歷
運行效果:
由此可見下標(biāo)是按1遞增的,沒有產(chǎn)生跳躍現(xiàn)象。
golang原生數(shù)據(jù)類型:按長度:int8(-128-127)、int16、int32、int64。
布爾型:布爾型的值只可以是常量true或者false。一個簡單的例子:varbbool=true。
數(shù)字類型:整型int和浮點型float32、float64,Go語言支持整型和浮點型數(shù)字,并且支持復(fù)數(shù),其中位的運算采用補碼。
字符串類型:字符串就是一串固定長度的字符連接起來的字符序列。Go的字符串是由單個字節(jié)連接起來的。Go語言的字符串的字節(jié)使用UTF-8編碼標(biāo)識Unicode文本。
派生類型:包括:(a)指針類型(Pointer)(b)數(shù)組類型?結(jié)構(gòu)化類型(struct)(d)Channel類型(e)函數(shù)類型(f)切片類型(g)接口類型(interface)(h)Map類型。