前言:
一如既往,繼續Go語言的學習,不過繼續學習之前,容許我再廢話幾句。最近發現堅持一件事情很重要,而且最近也發現堅持一件事情真的有點難。雖然文章基礎,不過我還是要堅持的,廢話完畢,那麼就繼續吧。
一 Go語言之字串
與大多數物件導向程式設計語言一樣,Go語言也具有string(字串)類型,只不過它與其它語言例如java中的String類型不一樣的是它是實值型別。並且注意聲明的關鍵字是string,全部小寫哦,親(java程式員尤其注意,c#程式員偷樂中......)。除此之外,它還有個特性就是不可變性,這裡需要注意的是指字串本身不可變並不是字串變數不可變,稍後看例子就能明白。在Go語言中string類型的結構如下:
1 struct String2 {3 byte* str;4 int32 len;5 };
上述結構可以在Go語言的原始碼中的runtime.h標頭檔中找到。
從上述結構,我們可以看出,其實string類型是由一個byte指標和int32類型的表示字串長度的變數兩部分組成。其中這裡的byte是uint8的別名,實質上它就表示8位的不帶正負號的整數,因此本質上在電腦上字串其實也就是數字而已。只不過,通過不同的編碼方式將數字映射到相應的字元上。而且在Go語言中使用的是UTF-8編碼方式。如果你還不明白所謂的編碼方式,那麼請自己通過網路查閱吧,因為涉及的知識點又會比較多,而今天我們只關注Go語言,所以這裡就不細說了。
以上結構是Go語言的runtime中的c語言的結構體,所以,實際上在Go語言中的string類型你可以理解成內部就是上面的結構,至於是如何?的,現在沒必要搞清楚,這關乎Go的語言底層實現了,暫時我們只需要使用就可以了。當然有興趣的也可以從底層去挖。
為了讓事情更好玩些,我們當然也可以在Go語言層面上類比下上面的結構,當然實際中是毫無意義的,看下面:
在main函數中首先聲明定義了一個animal的字串,然後將它轉成byte數組,並將它的地址傳給我們自訂的String結構體,但是String結構體的第一個參數不是一個指標類型嗎?沒錯,其實指標變數就是用來存放該類型的記憶體位址的變數,當它接收一個byte數組的首地址時,就可以控制數組了。所以,當我們傳遞給String結構體前面的那個b的byte數組的地址後,其實也就可以控制這個數組了。是不是已經暈了?嘿嘿,正常,當初剛學C語言的時候,筆者也一直沒明白指標。後來慢慢的就習慣了。再看30行,這的print是我們自己定義的列印這個結構體的函數,當我們傳入String結構體類型cat變數後,第16行,我們迴圈遍曆結構體的指標變數,列印出它的每一個byte,由於Go語言不能和C語言一樣直接進行指標運算,所以需要引入unsafe包,通過它進行運算,這裡就不詳細介紹了,如非需要瞭解可以查詢文檔,不過對於初學者來說沒什麼大的意義,而且Go本來就不建議直接指標運算,不然直接用C好了,嘿嘿。通過上面的一頓折騰,最終將byte轉成string列印出來,所以最後byte數組又被還原成string了。
看完上面一段,估計有讀者要罵了,Go語言那麼麻煩,比C語言還麻煩。請冷靜啊,上面的在實際開發中是幾乎很少用到的,不然還真不如直接用C語言了,我這裡寫這一大堆,只是想闡釋下它的內部結構,順帶練習下Go的結構體,完全沒明白的也不用管,或許等隨著我們的深入學習,時間久了,再回來看就能明白了哦。
二 字串操作
瞭解了字串的基本情況後,我們再來看看對於字串的操作。在上一節中,我們其實已經對字串求了它的長度,就是通過len函數。不過它求得的結果並不是字串中字元的個數,這似乎和其它一些的語言不太一樣,例如java。不過,當你賦值給它的都是英文字元的時候,似乎這個結果就是字元個數,但是當你將中文賦值給它後,就有些不太對了,不信可以試試。這裡我將開發平台切換到了Linux,因為在windows下命令提示字元下對於UTF-8的字元集操作不太方便。請看例子:
最終結果是:
結果是12,有圖有真相,為什麼是這個結果呢?原因是在Go語言中,字元是utf-8編碼的,其中英文字元一個算一個位元組,中文算兩個位元組。那麼,我們如果非要得到字元個數呢?可以將string轉換成[]rune類型:
rune沒啥好奇怪的,其實就是int32的別名,所以這裡其實是將string轉成了32位整數數組分別存入對應字元的unicode,這樣最終有幾個字元就對應幾個unicode分別位於數組中。因此最後可以得到長度為2。當然可以列印看下unicode是什麼:
接下來,來點輕鬆的,大家都知道python中對數組可以切片,在Go中,也可以。如下:
最終結果:
今天就到這裡,感覺文章越來越長了,額,沒辦法,隨著深入學習必然會這樣,但是我還是會盡量縮短每篇的長度的。希望對大家有協助~