Contents

Golang - 類型與聲明 (Types and Declarations)

本篇文章將介紹類型與聲明,基本上接觸過程式語言的話,許多部份是相似的,僅有少處不同。

如同其他的程式語言,Golang 也有許多與相同的類型:Boolean、Integer、Float與String,後續會分別介紹不同的類型。

但我比較喜歡使用宣告,後面若看到宣告意同聲明。(Declarations)

Zero Value

在 Golang 中,會默認 Zero Value分配給已經聲明,但未分配數值的任何變數,換句話說也可以被稱為預設值,不同的類型的 Zero Value 也有所不同。這裡列出了幾個常用的變數的 Zero Value。

【Zero Value 並不是代表為 0 !! 不同類型的變數有不同的 Zero Value !!】

Literal

Literal 簡單來說是在程式碼中賦予的數值、字元或是字串,例如:

func main(){
    fmt.Println("Hello World")
}

這裡的 "Hello World" 就是字串型態的 Literal。

Integer literal

若 Literal 為整數時,透過不同的前綴代表不同的進制方式。另外,當整數字串過長時,可以透過 underscore 將數字進行分組,提高閱讀的效能,但不能在該數字的開頭或結尾使用。

0b111 // 2進制
0o111 // 8進制
0x111 // 16進制
0111 // 這也是代表8進制,但容易搞混,不要使用這種方式!!
//b,o,x可以用大寫B,O,X代替,會是一樣的作用。

a := 1111
b := 1_111 // 這兩組代表的是相同的數字。

Float literal

若 Literal 為 float 時,可以使用字母 e 和數字組合出要使用的指數數值。與 Integer Literal 一樣能使用 underscore 提高閱讀的效能。

1.11e2 // 111.0

0.111_111 // 0.111111

另外, Float Literal有一種十六進制的表示方式。以 0x 作為前綴,指數後面以字母 P 為開頭進行運算。

0x1p-2 // 1.0 * (2^-2) = 1.0/4 = 0.25
0x2.p10 // 2.0 * 2^10 = 2048.0

Rune literal

通常代表字元,會用單引號包起來,常用來表示 Unicode 字元。

'a' // Unicode
'\141' // 8進制
'\x61' // 16進制

// 另外還有一些較特別且常使用的符號。
'\n' // newLine
'\t' // tab
'\'' // 單引號
'\"' // 雙引號
'\\' // 反斜線

String literal

如同前面所提到的 "Hello world",會使用雙引號建立一個字串,並包含0個或多個字元,若要使用換行、反斜線與雙引號時,請記得透過反斜線進行轉義,使用方式與前面介紹 Rune literal 的符號是一樣的。

Boolean

透過 bool 表示布林變數,布林具有 truefalse兩種數值,bool的 Zero Value 為 false

var flag bool
var status = true

Numeric Types (數值類型)

基本上可分為三類:整數、浮點數與一些不常使用的複雜類型。

整數 (integer)

基本上有各種大小的有符號數與無符號數。所有整數類型的 Zero Value 為 0 ,整數類型如下表所示:

類型名稱 數值範圍
int8 –128 to 127
int16 –32768 to 32767
int32 –2147483648 to 2147483647
int64 –9223372036854775808 to 9223372036854775807
uint8 0 to 255
uint16 0 to 65536
uint32 0 to 4294967295
uint64 0 to 18446744073709551615

另外, intuint 會因為開發環境的 CPU 而會是不同類型的整數,在32位元的CPU上會是 int32,uint32,在64位元的CPU上會是int64,uint64

然而,這麼多種的整數類型,要如何知道在何時使用其中一個呢?可以透過下述的三條規則去決定:

  • 若開發或使用在具有特定大小的整數之格式或協議,則使用相應的整數類型。
  • 若是撰寫一個用在任何整數類型的函式庫之函式時,請盡可能寫兩個函式,一個用 int而另一個使用uint。更加嚴謹的狀況下能規定大小會更好。(e.g. int64,uint64)
  • 其他情況下,使用 int 即可,除非因為效能或是特定目的,已知需要明確的整數大小與有無符號,否則請使用 int

浮點數 (float)

基本上分為兩種, float32float64,浮點數類型的 Zero Value 為 0。

類型名稱 最大絕對值 最小(非零)
float32 3.40282346638528859811704183484516925440e+38 1.401298464324817070923729583289916131280e-45
float64 1.797693134862315708145274237317043567981e+308 4.940656458412465441765687928682213723651e-324

除非是記憶體問題,否則請使用精度較好的 float64,但精度較好也不能明確的表示十進制數值,請不要使用浮點數代表金錢或是需要精確十進制表示的數值。

複雜 (complex)

基本上用於複數,有complex64與complex128兩種。(想到電學的交流電計算(頭痛))。但因為複數很少使用,我認為僅要知道有這個內置的類型即可。

運算子

常見的運算子 +, -, *, /, %,整數除法的結果仍會是整數,若需要有浮點數效果,則需使用類型轉換。

另外可以將任何運算子與 = 做結合修改變數:+=, -=, *=, /=, %=

比較的運算子則有 ==, !=, >=, >, <, <=

操作運算符則有:

<< // shift left
>> // shift right
& // logical AND
| // logical OR
^ // logical XOR
&^ // logical AND NOT

一樣可以與 = 結合修改變數:&=, |=, ^=, &^=, <<=, >>=

類型轉換

許多語言也有許多數字類型,且會在需要時自動類型提升,但自動轉換時可能會發生複雜的問題,並會有意想不到的結果。Go 作為嚴謹性高的語言,不允許自動類型提升,需要時要使用類型轉換才行。

var x int32 = 10
var y int64 = 20
var z int64 = int64(x) + y
var w float64 = float64(y) + float64(z)

聲明 (var, :=)

宣告變數有許多方法,而每一種方法都傳達了有關如何使用該變數的資訊。

最冗長的方法是使用 var、類型並賦予值。

var x int = 1

若等號右側的類型,是變數的預期類型,則可以省略等號左側的類型,

var x = 1 // type is int.

若宣告變數並將其設為Zero Value,則將等號右側刪除。

var x int 

並可以一次宣告多個變數,可以是相同的類型,或是不同的類型。

var x,y int = 1,2
var i,j int
var a,b = 1,"Hi"

還可以使用宣告列表(declaration list)一次宣告多個變數,但適用在函式外。

var(
    x   int
    y       = 1
    a,b     = 1,"Hi"
    i,j string
)

在函數中時,可以使用 := 替換掉 var 使用類型推斷的聲明。

var x = 10
x := 10 // 這兩行程式碼的作用是相同的。

一樣可以同時聲明多個變數,但這種不帶類型的宣告方式只能在函數中使用。

a,b := 1,"Hi"

:= 可以允許為現有的變數賦值,只要 :=左側有一個新的變數,則任何其他變數都可以存在。

x := 1
x,y := 2, "Hi"

在package宣告變數的話,則必須使用 var 宣告,在函式外使用 :=是不允許的。

另外有些情況下,盡量不要使用:=

  • 將變數初始化為 Zero Value 時,請使用 var 進行宣告,因為 Zero Value 是有意的。
  • 賦值的預設類型與變數的類型不同時,請使用 var
x := byte(20) 
// 這個不好,賦值的預設類型是int,但變數是 byte。雖然可以用類型轉換處理這個議題,但用 var 直接宣告清楚會好一點。
var x byte = 20
  • := 可以同時宣告新變數與現有變數,但使用上可能會有 shadow variable 的狀況發生,建議宣告新的變數時用var宣告,並用 = 賦予數值。

最後,盡量不在函式外宣告變數。會難以追蹤。

const

簡單來說,就是宣告一個數值,且該數值是不可變的。

const x int64 = 1
const (
    a = 1
    b = 2
)

變數命名

基本上沒有硬性規定,但還是建議遵循以下幾點。

  • 當變數名稱為多個單字組成時,採用駝峰式大小寫命名。
var studentScore int = 100
  • 變數名稱的第一個字母會確定是否能在 package 外被存取。
  • 在函式中,盡量使用較短的變數名稱,當該變數的範圍愈小,名稱就應該愈短。(e.g.跑迴圈時常使用 i 為變數(integer))
  • Go 是強類型語言,是不需要在變數名稱中加入預期的變數類型,與其加入變數類型,最好是再想一個更完整的名稱來宣告這個變數代表甚麼。

參考資料

  1. Learning Go(書籍)
  2. Basic Types and Basic Value Literals