深入Go語言 - 1
準備寫一個Go 語言深入開發的系列,分為三個部分。第一部分為Go 語言的深入剖析,第二部分為一些官方庫的深入開發,第三部分為一些第三方庫的介紹。
奇怪的變量名
標志符用來命名變量、類型、函數名等,最常規的,我們使用普通的拉丁字母和數字作為標志符,或者以下劃線開始。
str := "hello world"
fmt.Println(str)
_str09 := "hello w0rld"
fmt.Println(_str09)
但是根據Go語言規范,任何Unicode編碼的字符和下劃線都可以作為標識符的第一個字母,之后可以是任意的Unicode的字符或者數字。允許的unicode字符為Unicode分類中的Lu、Ll、Lt、Lm、Lo等字符,比如中文、希臘字母等。你可以在參考鏈接中查看相應的Unicode字符分類。
一個變量 := "hello 世界"
fmt.Println(一個變量)
???ǘΩ??? := "hello ?"
fmt.Println(???ǘΩ???)
標識符業可以是類型名、函數名等:
type學生struct{
姓名 string
}
type小學生 學生
type???interface{
}
func函數名() {
fmt.Println("I am a function")
}
當然,我相信絕大部分的程序員都會以普通的拉丁字母和數字作為標識符的,這樣閱讀起來更符合大眾的習慣。在搞怪的情況下,可以嘗試一下這些"奇怪"字符。
- https://en.wikipedia.org/wiki/List_of_Unicode_characters
- http://www.unicode.org/Public/UNIDATA/UnicodeData.txt
- http://www.fileformat.info/info/unicode/category/index.htm
預定義標識符
首先看下面一段代碼,看看是否能變易成功:
funcmain() {
varinil=100
fmt.Println(i)
varisSuccessbool=100
fmt.Println(isSuccess)
}
你肯定會說,不可能成功,類型不對呀。
沒錯,不可能將一個整數賦值給布爾類型的變量的。 那么你能不能加在方法外面加幾行,讓代碼編譯成功?
請注意,以下標識符實預先定義的標識符,而不是關鍵字,這意味著我們可以"覆蓋"這些標識符的定義。
Types:
boolbytecomplex64complex128errorfloat32float64
intint8int16int32int64runestring
uintuint8uint16uint32uint64uintptr
Constants:
truefalseiota
Zero value:
nil
Functions:
appendcapclosecomplexcopydeleteimaglen
makenewpanicprintprintlnrealrecover
比如加上下面幾行代碼,程序就可以編譯通過。
packagemain
import"fmt"
typenilint
typebooluint8
funcmain() {
varinil=100
fmt.Println(i)
varisSuccessbool=100
fmt.Println(isSuccess)
}
整數字面值
Go語言不像其它語言, 如C++、Java,在聲明數值類型的時候可以通過后綴如ll等表明變量的類型, 目前Go語言不提供這個功能。
如果值以0開始,則代表8進制。
如果值以0x或者0X開始,則代表16進制。
浮點數和其它語言的表示法相同。
復數表示法業和其它語言一致。
Rune
其它語言如Java、C#,字符串的字符操作很直觀,但是Go語言的字符串的實現比較特殊,這可能和Go設計者的幾位大牛有關,它保留著Unix和C的痕跡。
Java語言規范規定,Java的char類型是UTF-16的code unit,也就是兩個字節,字符串是UTF-16 code unit的序列,因此每個字符都是定長的,要想獲得某個位置字符,很容易計算出它的字節在字符串中的位置。
Go語言使用UTF-8作為字符串的內部編碼,所以在沒有byte字面量的情況下,字符串都是使用UTF-8編碼的。因此對于大部分字符串都是ascii字符的情況下,占用的內存空間就會大大減少,但是帶來的問題是,從字符串的字節slice中查找第n個字符比較麻煩,因為不能直接的計算出來。
這里通稱所有字母都為字符,其實是不準確的,在Unicodde規范中,它們稱之為 code point , 比如code point U+2318代表 ? 。
A 既是一個字符,也是一個code point: U+00E0。
code point有點拗口,所以Go語言用 rune 來表示,你只需記住它們是等價的即可。
rune有單引號定義,它包含單一的一個 code point。
varrrune='文'
fmt.Printf("%#U\n", r)
通過 range 可以遍歷一個字符串中所有的rune:
constnihongo ="one world世界大同"
forindex, runeValue :=rangenihongo {
fmt.Printf("%#U starts at byte position %d\n", runeValue, index)
}
因為字符串是以UTF-8編碼的,通過輸出可以看到ascii字母只用一個字節,而這幾個中文漢字每個漢字用了3個字節。
要想獲得字符串中包含幾個字符(rune),下面的方法是不對的,它返回的是字符處內部的字slice的長度((9 + 4*3 =21):
conststr ="one world世界大同"
fmt.Println(len(str))
我記得有個Go語言寫的框架,在獲取一篇文章的前N個字符的時候,就直接用 len 方法計算,這對于中文文章來說,肯定不對,截取的字符要少于期望的字符數,而且可能截取半個字符。
要想在字符串中操作rune,可以使用 package unicode/utf8 ,它提供了一組處理字符串和rune的方法,
比如我們正確計算一個字符串中包含的rune的數量:
fmt.Println(utf8.RuneCountInString(str))
字符串以兩端用雙引號包含的方式定義,允許使用轉義字符存在或者"\"+byte方式包含rune。
"Hello, world!\n"
"世界"
"\u65e5本\U00008a9e"
"\xff\u00FF"
"\uD800"http://非法
"\U00110000"http://非法
Rune和字符串互轉
直接通過 T(x) 類型轉換即可。
r := []rune(str)
fmt.Printf("%#v\n", r)
str = string(r)
fmt.Printf("%#v\n", str)
另外 package strconv 也提供了格式化rune為字符串的一些方法, 比如
s := strconv.QuoteRune('?')
fmt.Println(s)
來自: http://colobu.com/2016/06/15/dive-into-go-1/