Go的基本數據類型


這是 Go 學習筆記的第一篇,主要是 Go 基本數據類型的學習總結。
由於本人一直使用 PHP 語言進行開發,在學習 Go 的過程中發現有些知識點經常混淆,遂將 Go 與 PHP 做了比較(僅限於二者的基本數據類型)。
 
Go
PHP
基本數據類型
布爾型
數字類型:
  • 整型(int、unit)
  • 浮點型(float32、float64)
  • 其它:byte(類似unit8)、rune(類似int32)等
字符串類型
派生類型:
  • 指針類型(Pointer)
  • 數組類型(Array)
  • 結構類型(Struct)
  • 管道類型(Channel)
  • 函數類型(Function)
  • 切片類型(Slice)
  • 接口類型(Interface)
  • Map類型(Map)
4 種標量類型:
  • boolean(布爾型)
  • integer(整型)
  • float(浮點型,也稱作 double)
  • string(字符串)
3 種復合類型:
  • array(數組)
  • object(對象)
  • callable(可調用)
2 種特殊類型:
  • resource(資源)
  • NULL(無類型)
字符串
字節編碼
  • 字符串的字節默認使用 UTF-8 編碼
  • 支持 Unicode 字符
  • 只支持 256 的字符集,需要在代碼中顯式指定字符編碼 header("Content-Type: text/html;charset=utf-8"); 或修改php.ini中有關默認字符集的設置 default_charset = "utf-8" 
  • 不支持 Unicode 字符
字符串定義
  • 雙引號(""):雙引號中的轉義字符會被替換
  • 反引號(``):反引號中原生字符串中的轉義字符(如\n)會被原樣輸出
  • 單引號(''):單引號括起來的單個字符,需要格式化輸出,%c,否則輸出字符碼數
  • 雙引號(""):雙引號中的轉義字符會被替換,可以解析變量,即將變量包含在雙引號中
  • 單引號(''):與Go的反引號類似,轉義字符不會被轉義,原樣輸出
字符串長度

 len() :獲取的是每個字符的 UTF-8 編碼的長度和,而不是直接的字符數量。

如 len("hello,世界") 的結果是 12 不是 8

 strlen() :與 Go 的  len() 類似,得到的是字符串所占的字節數

 utf8.RuneCountInString() :獲取字符串的真正長度,上面的 utf8.RuneCountInString("hello,世界") 的結果是 8。

注:需import "unicode/utf8"

獲取字符串的真正長度可以使用下面兩個函數:
  •  mb_strlen() :需安裝 mbstring 擴展
  •  iconv_strlen() :返回字符串的字符數統計,是整型
字符串拼接
運算符 + :
str := "hello, " +
"world"
  • 字符串之間用加號“+”拼接。如果換行,+ 要放到當前行的末尾,不能放到下一行的開頭
  • 使用這種拼接方式,里面的字符串是不可變的,每次運算都會產生一個新的、臨時的字符串,給 GC 帶來額外的負擔,所以性能比較差
運算符 . :
$str = "hello, " . "world";
// 也可以寫成:
$str = "hello, " . "world";
  • 字符串之間用句點 “.”拼接,換行對句點的位置沒有要求
fmt.Sprintf():
fmt.Sprintf("%d:%s", 2018, "年")
  • 內部使用 []byte 實現,不會產生臨時的字符串
  • 內部邏輯復雜,還用到了interface,性能一般
strings.Join()
strings.Join([]string{"hello", "world"}, ", ")
  • Join會先根據字符串數組的內容,計算出一個拼接之后的長度,然后申請對應大小的內存,一個一個字符串填入
  • 已有一個數組的情況下,這種拼接方式的效率很高,但如果沒有,去構造這個數據的代價也不小。
bytes.Buffer——優先推薦
var buffer bytes.Buffer
buffer.WriteString("hello")
buffer.WriteString(", ")
buffer.WriteString("world")
 
fmt.Print(buffer.String())
  • 使用這種拼接方式,可以把字符串當成可變字符使用,對內存的增長也有優化
  • 如果能預估字符串的長度,還可以用 buffer.Grow() 接口來設置 capacity。
strings.Builder——推薦
var b1 strings.Builder
b1.WriteString("ABC")
b1.WriteString("DEF")
 
fmt.Print(b1.String())
  • 內部通過 slice 來保存和管理內容
  • 提供了 Grow() 來支持預定義容量,這樣可以避免擴容而創建新的 slice
  • 非線程安全,性能上和 bytes.Buffer 相差無幾
數組
聲明數組
  • 數組元素必須類型唯一,要么都是字符串,要么都是數字類型。如果想讓數組元素類型為任意類型,可以使用空接口interface{}作為類型,當使用值時必須先做一個類型判斷。
  • 聲明時需要確定長度,如果采用不定長數組的方式聲明,在初始化時會自動確定好數組的長度。
① var arr [2]int //var 數組名稱 [數組長度]數組元素類型
② var arr = [2]int{1,2} //var 數組名稱 = [數組長度]數組元素類型{元素1,元素2,...}
③ var arr = [5]string{3: "ab", 4: "cd"} //指定索引位置
④ var arr = [...]int{1,2} //var 數組名稱 = [...]數組元素類型{元素1,元素2,...},不定長數組聲明方式
⑤ new():創建的是數組引針,eg.  var arr1 = new([5]int) 
  • 聲明時不需要確定長度,且數組元素可以多類型混合
$arr  = ['a', 'b', 'c', 123];
 
如果是 Go,會報錯:
# command-line-arguments
./arr.go:6:34: cannot use 123 (type int) as type string in array or slice literal
值傳遞和
引用傳遞
var arr1 = new([5]int)
arr := arr1
arr1[2] = 100
fmt.Println(arr1[2], arr[2])
 
var arr2 [5]int
newarr := arr2
arr2[2] = 100
fmt.Println(arr2[2], newarr[2])
程序輸出:
100 100
100 0
new([5]int)創建的是數組指針,arr和arr1指向同一地址,故而修改arr1時arr同樣也生效;
而newarr是由arr2值傳遞(拷貝),故而修改任何一個都不會改變另一個的值。
達到與左側相同的效果,PHP 代碼如下:
$arr1 = [5, 10, 0, 20, 25];
$arr = &$arr1; //引用傳遞
$newArr = $arr1; //值傳遞
$arr1[2] = 100;
echo $arr1[2], $arr[2];
echo $arr1[2], $newArr[2];
 
程序輸出:
100 100
100 0
PHP中的引用傳遞使用 & 符號。
切片
定義
  • 切片是引用(對底層數組一個連續片段的引用),不需要占用額外的內存,比數組效率高
  • 一個切片未初始化前默認為nil,長度為0
  • 切片的長度可變,可以把切片看成一個長度可變的數組
PHP中沒有切片這個概念,但是在數組函數中有個 array_slice() 函數,可以根據 offset 和 length 返回指定的數組中的一段序列。與 Go 的切片相似。
$input = array("a", "b", "c", "d", "e");
$output = array_slice($input, 0, 3);   // returns "a", "b", and "c"
聲明
① 切分數組
var arr = [5]int{1,2,3,4,5} //數組
var s []type = arr[start:end:max] //切片(包含數組start到end-1之間的元素),end-start表示長度,max-start表示容量
② 初始化
var s = []int{2, 3, 5, 7, 11} //創建了一個長度為 5 的數組並且創建了一個相關切片。
③ 切片重組
var s []type = make([]type, len, cap) //len 是數組的長度也是切片的初始長度,cap是容量,可選參數
簡寫為slice := make([]type, len)
字典
定義
  • 一種元素對的無序集合,一組稱為元素value,另一組為唯一鍵索引key
  • 未初始化 map 的值為 nil。map 是引用類型
  • map 可以動態增長,聲明時不需要定義長度
PHP的關聯數組類似於 Go 的 Map。
聲明
var mapName map[keyType]valueType
② var mapName map[keyType]valueType{k1:v1, k2:v2, ...}
var mapName = make(map[keyType]valueType, cap) //cap是可選參數,表示容量
其實 Go 的基本數據類型的知識點以及它和 PHP 的區別絕不止上面列出的這些,對比新舊兩種語言的差別意義也不是很大,但對我來說,通過梳理可以達到溫故知新的目的。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM