ETH官方钱包

前往
大廳
主題 達(dá)人專欄

只要學(xué)過 C 語(yǔ)言馬上就會(huì)!Go 語(yǔ)言的資料型態(tài)

解凍豬腳 | 2021-10-03 19:15:01 | 巴幣 1792 | 人氣 1794

 
其實(shí)構(gòu)思這系列的時(shí)候思考了很久,因?yàn)?Golang 有很多常用觀念要結(jié)合起來(lái)才能發(fā)揮出它的功能和特色,這導(dǎo)致 Golang 的教學(xué)文不太容易能像 C 語(yǔ)言系列文那樣明確地個(gè)別獨(dú)立成一類主題來(lái)講。我曾經(jīng)提到建議在具備一些程式語(yǔ)言基礎(chǔ)之後才來(lái)學(xué) Golang,也正是如此。

這篇文可能會(huì)預(yù)設(shè)你已經(jīng)具有這方面知識(shí)而省略一些東西,除此之外也會(huì)有些我認(rèn)為可以晚點(diǎn)再說(shuō)的觀念被我排到之後的章節(jié)。如果有什麼地方讓你覺得卡住,就再請(qǐng)你到文章底下留言吧!


? 基本的資料型態(tài)

在使用變數(shù)以前,我們要先瞭解 Golang 有哪些常見的資料型態(tài)(型別)。

Golang 的基本型別非常簡(jiǎn)單,我們可以粗分成以下幾類:
。int(整數(shù))
。float(浮點(diǎn)數(shù))
。bool(布林值)
。string(字串)
。complex(複數(shù))

光是使用上面幾種,就已經(jīng)足以應(yīng)付大部分日常情況。對(duì)於一個(gè)已經(jīng)有程式語(yǔ)言基礎(chǔ)的人而言,相信至少 int、float、bool、string 這四樣都不是什麼很陌生的東西吧?


? 變數(shù)的宣告方式

宣告變數(shù)主要有兩種方式,一種是使用 var 關(guān)鍵字,一種是使用「:=」符號(hào)來(lái)宣告並賦予初始值。

以下幾種方法都是 OK 的,使用 := 符號(hào)的話就不需要再用 var 關(guān)鍵字了,因?yàn)檫@個(gè)冒號(hào)本身就有宣告新變數(shù)的意義:

package main

import "fmt"

func main() {
    var a = 8
    var b int
    var c int = 561
    d := 32
    e := int(77)
    fmt.Println(a, b, c, d, e) // -> 8 0 561 32 77
}

但如果你想在函式外面宣告能夠給不同函式共用的全域變數(shù)(global variable),就只能用 var 關(guān)鍵字來(lái)宣告:

package main

import "fmt"

var money = 300

func main() {
    fmt.Printf("I have $%d.", money) // -> I have $300.
}

和 C 語(yǔ)言不同的是,Golang 在宣告變數(shù)的時(shí)候不需要擔(dān)心殘值問題,每一種型態(tài)都有預(yù)設(shè)的 zero-value——假如你在宣告 int 的時(shí)候沒有給予初始值,就會(huì)預(yù)設(shè)是 0。

如果你想瞭解 C 語(yǔ)言的殘值現(xiàn)象,可以參考跟著豬腳 C 起來(lái):用電腦來(lái)操控資料吧

除此之外,你也能利用逗號(hào)在一行之內(nèi)同時(shí)宣告多個(gè)變數(shù):

ar m, n int = 32, 99
p, q := 64, 188

或者是用來(lái)單純賦值:

var x, y int
x, y = 9, 17

甚至是使用括號(hào)來(lái)宣告很多個(gè)變數(shù)(或賦值):

var (
    class int
    money = 114514
    age = 24
    job = "student"
)

一般來(lái)說(shuō)如果在沒有非常講究變數(shù)型態(tài)的地方(例如 for 迴圈的迭代變數(shù) i),我們直接使用 := 符號(hào)來(lái)宣告變數(shù)就可以了,畢竟我們本來(lái)就不怎麼在乎它的型態(tài),這麼做也相對(duì)使得 code 更簡(jiǎn)潔:

for i := 0; i < 10; i++ {
    fmt.Print(i)
} // -> 0123456789


? 定義常數(shù)

就像其他語(yǔ)言的常數(shù)一樣,常數(shù)用來(lái)定義在整個(gè)程式流程裡不需要被修改的內(nèi)容。在 Golang 定義常數(shù)(contant)的方法也很簡(jiǎn)單,只要用 const 關(guān)鍵字就行了:

const pi = 3.14159
const e float64 = 2.71828
const sqrt2, sqrt3 = 1.41421, 1.73205

它也一樣可以使用括號(hào)把相關(guān)的擺在一起,更加美觀:

const (
    log2 = 0.30103
    log3 = 0.47712
    log5 = 0.69897
)

如果這些常數(shù)是遞增的整數(shù)(通常用在編號(hào)),你可以用 iota 關(guān)鍵字,Golang 會(huì)自動(dòng)把它從 0 開始往下數(shù),然後定義好:

const (
    Cat = iota
    Dog
    Hamster
    Bird
    Pig
)

func main() {
    fmt.Println(Cat, Dog, Hamster, Bird, Pig) // -> 0 1 2 3 4
}

如果你希望這些編號(hào)從 n 開始數(shù),就用 iota+n:

const (
    Cat = iota + 5
    Dog
    Hamster
    Bird
    Pig
)

func main() {
    fmt.Println(Cat, Dog, Hamster, Bird, Pig) // -> 5 6 7 8 9
}

iota 並不是沒有用處,這就有點(diǎn)像是 C 語(yǔ)言的 enum 功能。我們有些場(chǎng)合並不在乎這些常數(shù)的實(shí)際數(shù)值內(nèi)容,而是直接把這些常數(shù)當(dāng)成是一種符號(hào)來(lái)使用,目的是在讓程式碼變得更能一眼就看懂。像是我們?yōu)g覽網(wǎng)站的時(shí)候偶爾遇上問題,會(huì)看到例如 403(禁止訪問)、404(找不到檔案)這種 HTTP 協(xié)定裡面的標(biāo)準(zhǔn)錯(cuò)誤編號(hào)。

假如在程式裡面老是直接用 404 來(lái)表達(dá)「找不到檔案」的錯(cuò)誤代碼,程式碼一旦多了就會(huì)變得很難閱讀(也不易統(tǒng)一修改,要是不慎寫錯(cuò)的話也難以察覺),不如直接令 const ErrorNotFound = 404,然後用 ErrorNotFound 來(lái)表示這個(gè)錯(cuò)誤編號(hào),寫出來(lái)的程式豈不漂亮多了嗎?


? 各種型態(tài)的家族

在 Golang 裡面,整數(shù)型態(tài) int 可以細(xì)分成 int、int8、int16、int32、int64、uint、uint8、uint16、uint32、uint64。這些不同的 int 類型看起來(lái)好像很複雜,但其實(shí)只是差在佔(zhàn)用的位元數(shù)量(8, 16, 32, 64)、是否無(wú)號(hào)(unsigned)而已。當(dāng)你需要儲(chǔ)存更大範(fàn)圍的數(shù),就使用更多位元數(shù)的 int;當(dāng)你能百分之百肯定你不會(huì)存入負(fù)數(shù),就使用 unsigned 的型態(tài)。

關(guān)於 unsigned integer,可以參考跟著豬腳 C 起來(lái):各式各樣的資料型態(tài)

通常情況下,我們會(huì)直接使用 int 來(lái)儲(chǔ)存整數(shù)——int 型態(tài)佔(zhàn)用的位元組數(shù)量(和可以表示的範(fàn)圍)會(huì)依照平臺(tái)而定,如果是在 32-bit 的系統(tǒng)的話,這個(gè) int 的範(fàn)圍就會(huì)和 int32 一樣,在 64-bit 的系統(tǒng)裡面則會(huì)和 int64 一樣。只是,Golang 不允許我們把這些東西通通混在一起,所以 int、int32、int64 都是不能直接互通的。我們?nèi)绻氚?int32 型態(tài)的值取出來(lái)存到 int 的變數(shù)裡,需要先透過顯式轉(zhuǎn)換來(lái)明確地表示它被轉(zhuǎn)換成什麼樣的型別,才能繼續(xù)操作:

var a int = 555
var b int32 = 777
// you should do a = int(b) instead of a = b
a = int(b)

浮點(diǎn)數(shù)則分為 float32 和 float64。注意,浮點(diǎn)數(shù)不像 int 一樣,你要嘛就用 float32、要嘛就用 float64,只能從這兩種選一個(gè)。一般我們比較多會(huì)使用 float64,如果你在宣告的時(shí)候使用諸如 var a = 0.0 或是 a := 0.0 之類的句式,編譯器會(huì)預(yù)設(shè)為 float64。

至於上面提到的複數(shù),分為 complex64 和 complex128 兩種(複數(shù)預(yù)設(shè)會(huì)是 complex128)。其中 complex64 是由兩個(gè) float32 組成,而 complex128 則是由兩個(gè) float64 組成,分成兩個(gè)是因?yàn)橐粋€(gè)要用來(lái)存放實(shí)部、一個(gè)用來(lái)存放虛部:

var j = 7 - 4i // complex128 as default
var k complex128 = 3 + 5i
var h = complex(9, -5) // same as (9-5i)

由於使用 complex64/complex128 型態(tài)的機(jī)會(huì)實(shí)在太少,這方面我就不再多著墨,大家可以稍微看看就好。只是作為一個(gè)通用的語(yǔ)言來(lái)說(shuō),Golang 竟然提供複數(shù)的內(nèi)建型態(tài),我覺得很神奇就是了。


? 型態(tài)別名與型態(tài)定義

當(dāng)你需要用某些套件處理資料流(例如 JSON parser、檔案讀寫)的時(shí)候,你可能會(huì)見到有人使用 byte 型態(tài)。其實(shí),在 Golang 裡面的 byte 型態(tài)就跟 uint8 並沒有任何不同,它們甚至是完全相容的:

var a byte = 66
var b uint8
b = a

這就是所謂的別名(alias),你高興的話也可以自己替任一個(gè)型態(tài)來(lái)定義別名:

package main

import "fmt"

type bit = bool

func main() {
    var a bool = true
    var b bit
    b = a
    fmt.Println(b)
}

雖然看似沒有什麼意義,但這麼做的話就會(huì)有更方便閱讀、理解程式碼內(nèi)容的優(yōu)點(diǎn)。像是比起 uint8,如果我們使用 byte 型態(tài)來(lái)處理檔案資料流,就會(huì)更能體現(xiàn)「以 byte 為單位」的意義,畢竟只要一眼就可以看得出這是代表一個(gè)位元組了。除此之外,Golang 也有一個(gè)資料型態(tài) rune 是 int32 的別名,可以用來(lái)處理 unicode 字元。

不單單只有型態(tài)別名,有個(gè)和型態(tài)別名很相似的做法:

type bit bool

少了一個(gè)等號(hào),這樣就可以讓自訂的 bit 無(wú)法直接和原先的 bool 互通了:

var a bool = true
var b bit
b = a // -> cannot use a (variable of type bool) as bit value in assignment

這是為了在某些情況下我們可能會(huì)需要定義一些無(wú)法直接互通的型態(tài)(例如 ErrorCode、Color 之類的東西,搭配 iota 來(lái)定義),同樣也是為了讓程式碼變得更好閱讀或使用,就像這樣:

type color int

const (
    ColorBlack color = iota
    ColorWhite
    ColorRed
    ColorBlue
    ColorYellow
    ColorGreen
    ColorOrange
    ColorPink
)

func GetColorRGB(c color) string {
    switch c {
    case ColorBlack:
        return "#000000"
    case ColorWhite:
        return "#FFFFFF"
    case ColorRed:
        return "#FF0000"
    case ColorBlue:
        return "#0000FF"
    case ColorYellow:
        return "#FFFF00"
    case ColorGreen:
        return "#00FF00"
    case ColorOrange:
        return "#FF7F00"
    case ColorPink:
        return "#FFA5A5"
    default:
        return ""
    }
}


當(dāng)然也不是指完全就不能互通啦。以上面的兩個(gè)例子來(lái)說(shuō),如果你用 bit(a) 把 bool 轉(zhuǎn)型成 bit,或是用 color() 把一個(gè) int 的變數(shù)轉(zhuǎn)成 color 型態(tài),那也是沒問題的,端看身為設(shè)計(jì)者的你如何面對(duì)你自己(或是你手上的案件)有什麼樣的需求。

關(guān)於資料型態(tài)就說(shuō)到這裡吧,下次再來(lái)講講函式的各種功能,開始進(jìn)入 Golang 的核心。




縮圖素材原作者:Renée French(CC BY-SA 3.0)
送禮物贊助創(chuàng)作者 !
61
留言

創(chuàng)作回應(yīng)

Nick
最近想用go寫個(gè)簡(jiǎn)單的小遊戲
2021-10-04 00:49:57
解凍豬腳
簡(jiǎn)單的小遊戲,那要看是寫什麼樣的遊戲
如果有圖形介面的話個(gè)人不建議純 Go,搭配其他語(yǔ)言應(yīng)該會(huì)比較好
2021-10-04 00:52:19
Nick
沒有圖形介面 單純練習(xí)寫格大型一點(diǎn)的程式 還有網(wǎng)路的觀念
2021-10-04 00:57:55
蠢月
豬腳好聰明
2021-10-04 02:15:48
解凍豬腳
不我是笨蛋 [e3]
2021-10-04 22:52:44
? 小紅帽向創(chuàng)作者進(jìn)行贊助 ?
OwO)b
2021-10-04 16:00:34
解凍豬腳
帽帽…我今晚睡覺不會(huì)鎖門了
2021-10-04 22:52:57
? 勳章向創(chuàng)作者進(jìn)行贊助 ?
2021-10-08 20:52:08
解凍豬腳
感謝贊助![e38]
2021-10-09 00:42:29
追蹤 創(chuàng)作集

作者相關(guān)創(chuàng)作

更多創(chuàng)作