昨天介紹了在 Go 語言中的數字型別,今天來一口氣學會剩下三個型別吧!
在 Go 語言中我們把布林值 (Boolean) 簡稱為 bool,如大家所知,bool 內只有兩個值,不是 true 就是 false ,而在 bool 中的零值就是 false。
當我們將兩個值做比較時,結果一定為 bool 。
範例 1:
package main
import "fmt"
func main(){
fmt.Println(5 < 10)
fmt.Println(10 == 5)
}
範例 1(執行結果):
true
false
在鐵人賽第 6 天,我們有介紹到 if...else 邏輯判斷,其中 if 後面要接 true 的運算式,這時就是 bool 出場的好時機,讓我示範將範例一改寫成 if...else 邏輯判斷,相信對大家來說是一塊小蛋糕!
範例 2:
package main
import "fmt"
func main(){
if 5 < 10 {
fmt.Println("5 小於 10 是 true")
}
if 10 == 5 {
fmt.Println("10 等於 5 是 true")
} else {
fmt.Println("10 等於 5 是 false")
}
}
範例 2(執行結果):
5 小於 10 是 true
10 等於 5 是 false
在 Go 語言中的文字型別,就稱為字串 (String)。 (比起昨天複雜的數字友善多了^^)
當你在 Go 程式中寫文字的值時,就稱為字串常值(string literal) (等等你剛剛不是說叫做字串?現在又說叫做字串常值?根本愛情的騙子QQ) ,仔細看 字串 是指 型別 ; 字串常值 是指 值 ,但我個人認為大家知道個觀念即可,平常統稱為字串都是可以的。但還是要讓大家知道一下字串常值又分為以下兩種:
範例 3:
package main
import "fmt"
func main() {
rawText1 := `我是用反引號包住的字串們`
rawText2 := `\t我也是用反引號包住的字串們`
interpretedText := "\t我是用雙引號包住的字串們" // \t 代表水平 tab 空格
fmt.Println("rawText1",rawText1)
fmt.Println("rawText2",rawText2)
fmt.Println("interpretedText",interpretedText)
}
範例 3(執行結果):
rawText1 我是用反引號包住的字串們
rawText2 \t我也是用反引號包住的字串們 // 用反引號會原封不動地印出
interpretedText 我是用雙引號包住的字串們 // 用雙引號會轉譯字串再印出,所以可以看到他有了 tab 空格
那我們該什麼時候使用反引號,什麼時候雙引號呢?
範例 4:
package main
import "fmt"
func main() {
rawText := `我是用"反引號"包住的\字串\們~` // 若有很多符號需印出,可以把大家都裝在反引號裡
interpretedText := "我是用\"雙引號\"包住的\\字串\\們" // 若在雙引號裡還是需要有符號的話,需在符號前使用反斜線「\」,告訴程式碼他是真的符號啦
fmt.Println("rawText",rawText)
fmt.Println("interpretedText",interpretedText)
}
範例 4(執行結果):
rawText1 我是用"反引號"包住的\字串\們~
interpretedText 我是用"雙引號"包住的\字串\們
Rune 是一個有足夠空間可以容納 UTF-8 字元的型別,在 Go 語言中字串都是用 UTF-8 來編碼的,那 UTF-8 又是什麼呢?來看看維基百科的介紹。
UTF-8(8-bit Unicode Transformation Format)是一種針對 Unicode 的可變長度字元編碼,也是一種字首碼。它可以用一至四個位元組對Unicode字元集中的所有有效編碼點進行編碼。
簡單來說我們平常看到的每個字都有自己對應的字元編碼,而 UTF-8 他可能是 1~4 個編碼組成,主要是因為有中文或是其他語系,所以會有更多編碼的組合。
在 Go 語言中文字以 string 儲存時,會用 byte 來儲存所有字串,但是 string 是唯讀的 byte ,代表說有些超過兩位元以上的 UTF-8 會被拆開來儲存,這可能會在轉換時發生不如預期的結果,為了安全處理字串,建議可以先 將字串從 byte 集合轉換成 Rune 集合 。
範例 5:
package main
import "fmt"
func main(){
myName := "Krystal_奇犽老婆" // 我的名字是 12 個字元組成(含底線)
for i := 0; i < len(myName); i++ {
fmt.Print(myName[i]," ")
}
}
範例 5(執行結果):
75 114 121 115 116 97 108 95 229 165 135 231 138 189 232 128 129 229 169 134 % // 但印出來卻有 20 個數值,是因為 "奇犽老婆" 四個字是由兩位元以上組成的
那我們再把剛剛的範例修改一下,將位元數在轉回字串印出
範例 6:
package main
import (
"fmt"
)
func main(){
myName := "Krystal_奇犽老婆"
for i := 0; i < len(myName); i++ {
fmt.Print(string(myName[i])," ")
}
}
範例 6(執行結果):
K r y s t a l _ å ¥ ç ½ è å © % // 這邊這些奇怪符號便是因為他是多個位元組成,帶因爲轉回字串時,被拆開解讀,所以也印不回原本的 "奇犽老婆" 。
範例 4 就如同我上面所說的在轉換時發生不如預期的結果,所以我們為了安全處理字串,可以先將字串從 byte 集合轉換成 Rune 集合。
範例 7:
package main
import (
"fmt"
)
func main(){
myName := "Krystal_奇犽老婆"
runes := []rune(myName) // 先把 myName 字串轉成 rune 切片
for i := 0; i < len(runes); i++ {
fmt.Print(string(runes[i])," ") // 再把剛剛轉為 rune 切片轉字串印出
}
}
範例 7(執行結果):
K r y s t a l _ 奇 犽 老 婆 % // 登登!就跟原來一樣啦~
這時候好奇寶寶我本人立馬產生疑問啦!那這樣我是要怎麼知道哪些字是由兩位元以上組成的?所以這邊教大家一個 Go 裡內建的函式 len(),可以用來計算字串的字元長度。
範例 8:
package main
import (
"fmt"
)
func main(){
myName := "Krystal_奇犽老婆"
fmt.Println("bytes:",len(myName)) // 字串長度 bytes 數
fmt.Println("runes:",len([]rune(myName))) // rune 集合長度
}
範例 8(執行結果):
bytes: 20
runes: 12
可以透過這種方式來確認位元數,然後先將字串轉換成 Rune 集合,就可以安全無誤的使用字串啦!
補充:
在 Go 語言裡,每當用 for i 迴圈,來讀取 rune 切片時,會自動將其轉換成 for range 迴圈,便是每次從集合取出一個鍵 (key) 與值 (value) ,而下一輪迴圈就換下一組,當然也可以直接寫成 for range 迴圈。
在鐵人賽第 3 天的時候,我們有介紹過,指標(pointers)、函式(function)、介面(interface)、切片(slice)、通道(channel)及映射表(map)的零值為 nil。
那 nil 到底是什麼呢?我知道我知道因為這篇是在介紹型別,所以 nil 是一種型別,但其實不是的喔!在 Go 語言中 nil 值 不是型別 ,而是一種特殊的資料值,它代表 無型別 或是 無值 。 (好啊你這愛情騙子又來了)
前幾天有介紹到,當我們在處理 error 值時,需要先確認他不是 nil,或是當你今天想要對一個 nil 值做運算的時候,也是會直接爆錯的,因為他代表 無型別 或是 無值 ,你想對一個什麼都不是的東西做事,那有錯誤也是正常的,至於我們要如何避免錯誤發生呢?那便是當我們今天不確定這個值是不是 nil 值時,可以先加一層判定,如此一來便可以避免出錯了。
範例 9:
package main
import (
"fmt"
)
func main(){
var name *string // 用 var 宣告 name 指標變數,初始值為 nil
if name == nil {
fmt.Println("OMG 這個 name 是 nil 值")
}else{
fmt.Println("恭喜你成功宣告一個指標")
}
}
範例 9(執行結果):
OMG 這個 name 是 nil 值
用範例複習鐵人賽第四天的指標,加上簡單的 if...else 判斷,即可避免錯誤的發生!
終於介紹完 Go 語言的核心型別了,那明天繼續來介紹複合型別裡的陣列 (Array) ,明天見~~