iT邦幫忙

2022 iThome 鐵人賽

DAY 12
0
自我挑戰組

跟著 Go 實戰聖經 一起自學 Go系列 第 12

DAY 12 Go 語言 的核心型別 - 布林值 (Boolean) 、字串 (String) 及 nil 值

  • 分享至 

  • xImage
  •  

昨天介紹了在 Go 語言中的數字型別,今天來一口氣學會剩下三個型別吧!

布林值 (Boolean) : true 或 false

在 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

字串 (String)

在 Go 語言中的文字型別,就稱為字串 (String)(比起昨天複雜的數字友善多了^^)

當你在 Go 程式中寫文字的值時,就稱為字串常值(string literal) (等等你剛剛不是說叫做字串?現在又說叫做字串常值?根本愛情的騙子QQ) ,仔細看 字串 是指 型別 ; 字串常值 是指 ,但我個人認為大家知道個觀念即可,平常統稱為字串都是可以的。但還是要讓大家知道一下字串常值又分為以下兩種:

  1. 原始值(raw):是在兩個反引號(`)內包住的字串,你怎麼寫他就原封不動地呈現。
  2. 轉譯值(interpreted):是在兩個雙引號(")內包住的字串,會根據 go 的規則轉換某些字,然後呈現。

範例 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 (符文)

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 迴圈。

nil 值

在鐵人賽第 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) ,明天見~~


上一篇
DAY 11 Go 語言 的核心型別 - 數字
下一篇
DAY 13 Go 語言 的複合型別 - 陣列 (array)
系列文
跟著 Go 實戰聖經 一起自學 Go30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言