文章目錄
- 整數
- 浮點數
- 復數
- 布爾值
- 字符串
- 字符串字面量
- Unicode
- UTF - 8
- 字符串和字節 slice
- 字符串和數字的相互轉換
- 常量
- 常量生成器 iota
- 無類型常量
整數
分類
- Go 的整數類型按大小分有 8 位、16 位、32 位、64 位 ,同時有符號整數包括
int8
、int16
、int32
、int64
,無符號整數包括uint8
、uint16
、uint32
、uint64
。int
和uint
大小依平臺而定,可能是 32 位或 64 位 。 rune
是int32
同義詞,用于指明 Unicode 碼點 ;byte
是uint8
同義詞,強調原始數據 。uintptr
用于底層編程存放指針,大小不明確 。
范圍
- 有符號整數以補碼表示,最高位為符號位,
n
位有符號整數取值范圍是-2^(n - 1)
到2^(n - 1) - 1
;無符號整數取值范圍是0
到2^n - 1
,如int8
取值范圍是-128
到127
,uint8
取值范圍是0
到255
。
運算
- 二元操作符:涵蓋算術、邏輯和比較運算,按優先級分五級,同級別運算滿足左結合律 。算術運算符(
+
、-
、*
、/
、%
)中,取模運算%
僅用于整數,除法運算/
在整數相除時結果為整數 。運算結果超出類型范圍會溢出,溢出高位部分丟棄 。比較運算符用于比較同類型整數,結果為布爾型 。 - 一元操作符:有一元加法(
+x
,等同于0 + x
)和一元減法(-x
,等同于0 - x
) 。 - 位運算符:包括
&
(位運算 AND )、|
(位運算 OR )、^
(位運算 XOR )、&^
(位清空 AND NOT )、<<
(左移 )、>>
(右移 ) 。位運算符對操作數逐位運算,不涉及算術進位或正負號 。左移運算x << n
等價于x
乘以2^n
,右移運算x >> n
等價于x
除以2^n
向下取整 ,有符號整數右移按符號位填充 。
類型轉換
- 不同整數類型間轉換需顯式轉換 。算術和邏輯(不含移位 )二元運算符要求操作數類型相同 ,否則需轉換為同一類型 。整數與浮點型相互轉換可能改變值或損失精度 ,浮點型轉整型會舍棄小數部分 。
- 底層數據結構相同但數據名稱不同也需類型轉化,如
tpye MyInt int
,MyInt
類型數據無法賦值給int
類型數據。
Go中無隱式類型的轉化。
格式化輸出
- 整數可寫成十進制、八進制(以
0
開頭 )、十六進制(以0x
或0X
開頭 ) 。使用fmt
包輸出整數時,可用%d
(十進制 )、%o
(八進制 )、%x
(十六進制 )等謂詞指定進制 。
浮點數
- Go 語言有
float32
和float64
兩種浮點數類型,算術特性遵循 IEEE 754 標準 。float32
有效數字約 6 位,float64
約 15 位 ,應優先選用float64
,因float32
運算易累積誤差 。
范圍與表示
math
包給出浮點值極限,math.MaxFloat32
約為3.4e38
,math.MaxFloat64
約為1.8e308
,最小正浮點數分別約為1.4e - 45
和4.9e - 324
。浮點數在源碼中可寫成小數(小數點前后數字可省略 )或科學記數法(如6.02214129e23
) 。- 通過
fmt.Printf
的%g
謂詞可輸出浮點值,也可用%e
(有指數 )或%f
(無指數 ) 。
特殊值
math
包含創建和判斷 IEEE 754 標準特殊值(正無窮大、負無窮大、NaN )的函數 。math.IsNaN
判斷參數是否為非數值,math.NaN
返回非數值 。與 NaN 比較除!=
外總不成立 。
運算與應用
- 函數返回浮點型且可能出錯時,最好單獨報錯 。
復數
- Go 語言有
complex64
和complex128
兩種復數類型,分別由float32
和float64
構成 。
操作函數
complex
函數用于根據給定實部和虛部創建復數,如var x complex128 = complex(1, 2)
創建復數1 + 2i
。real
函數提取復數實部,imag
函數提取虛部,如real(x*y)
、imag(x*y)
。
表示
- 在源碼中,浮點數或十進制整數后緊跟
i
表示虛數(實部為 0 ),如3.141592i
、2i
,復數常量可與其他常量相加,如1 + 2i
。可用==
和!=
判斷復數是否相等,需實部和虛部都相等 。 math/cmplx
包提供復數運算庫函數,如cmplx.Sqrt(-1)
計算復數平方根 。
布爾值
bool
型值即布爾值,只有true
(真 )和false
(假 )兩種取值 。if
和for
語句中的條件以及比較操作符(如==
、<
)的運算結果都是布爾值 。一元操作符!
表示邏輯取反,如!true
為false
,且(!true==false)==true
。代碼風格上,x==true
常簡化為x
。
運算規則
- 布爾值可通過
&&
(邏輯與 )和||
(邏輯或 )組合運算,存在短路行為:當&&
左邊操作數為false
,或||
左邊操作數為true
時,右邊操作數不會計算 。例如s != "" && s[0] == 'x'
,若s
為空字符串,不會計算s[0]
。 &&
和||
優先級高于==
和<
,形如'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9'
這樣的條件表達式無需加括號 。
與C++,Java等,運算規則相同。
與數值的轉換
- 布爾值不能隱式轉換成數值(如 0 或 1 ),反之亦然 。若需轉換,要使用顯式
if
語句,如if b { i = 1 }
。
字符串
- 字符串是不可變的字節序列,可包含任意數據,主要用于存儲人類可讀文本,文本字符串按 UTF - 8 編碼的 Unicode 碼點序列解讀 。
操作函數與運算
- 長度獲取:內置
len
函數返回字符串字節數,如len("hello, world")
結果為12
。 - 字符訪問:通過下標操作
s[i]
獲取第i
個字符(0 ≤ i < len(s)
),訪問越界會觸發宕機異常 。非 ASCII 字符的 UTF - 8 碼點可能占多個字節,所以第i
個字節不一定是第i
個字符 。 - 子串生成:用
s[i:j]
生成子字符串,從下標i
(含 )到j
(不含 ),結果長度為j - i
,i
和j
默認值分別為0
和len(s)
,下標越界或j < i
會觸發宕機異常 。 - 字符串連接:用加號
+
連接兩個字符串生成新字符串,如"goodbye" + s[5:]
。 - 字符串比較:可通過
==
和<
等比較運算符比較,按字節進行字典排序 。
不可變性
- 字符串值不可改變,不能直接修改字符串內部字節,如
s[0] = 'L'
會編譯報錯 。可通過+=
等方式生成新字符串并賦值給原變量實現拼接等操作 。字符串不可變性使得字符串及其子串可安全共用底層內存,復制和子串生成操作開銷低 。
存儲方式
字符串字面量
常規字符串字面量
- 形式:帶雙引號的字節序列,如
"Hello, 世界"
。由于 Go 源文件按 UTF - 8 編碼,字符串也按 UTF - 8 解讀,可寫入 Unicode 碼點 。 - 轉義序列:以反斜杠
\
開始,用于插入特定字節或表示 ASCII 控制碼等,如\a
(“警告” 或響鈴 )、\n
(換行符 )、\"
(雙引號 )、\\
(反斜杠 )等 。還可包含十六進制(\xhh
,h
為十六進制數字 )或八進制(\ooo
,o
為八進制數字 )轉義字符來表示單個字節 。
原生字符串字面量
- 形式:用反引號包裹,如:
const GoUsage = `Go is a tool for manageing Go source code.
Usage:go command [arguments]
...`
- 特性:轉義序列不起作用,內容嚴格按字面寫法,包括反斜杠和換行符,可跨多行書寫,回車符會被刪除以保證字符串在各平臺值相同 。適用于正則表達式、HTML 模板、JSON 字面量、命令行提示信息等場景 。
Unicode
從 ASCII 到 Unicode 的演進
-
早期軟件主要處理 ASCII 字符集,US - ASCII 碼用 7 位表示 128 個字符,包含英文字母、數字、標點等,能滿足早期計算機行業需求,但無法支持其他語言的文字體系 。隨著互聯網發展,數據包含多種語言,ASCII 無法滿足需求,于是出現了 Unicode 。
-
定義:Unicode 囊括世界上所有文書體系的字符,給每個字符賦予標準數字,即 Unicode 碼點 。
-
Go 語言實現:在 Go 語言中,這些字符記號稱為文字符號(
rune
),Unicode
第 8 版定義超 100 種語言文字的 12 萬個字符碼點 。Go 采用int32
類型保存單個文字符號,rune
是int32
的別名 。可將文字符號序列表示成int32
值序列,即 UTF - 32 或 UCS - 4 編碼,每個碼點編碼長度固定為 32 位 。但這種編碼因多數文本是 ASCII 碼(每個字符 8 位 ),會造成存儲空間浪費,且多數常用字符用 16 位就能容納。
UTF - 8
編碼原理
- UTF - 8 是以字節為單位對 Unicode 碼點作變長編碼,由 Ken Thompson 和 Rob Pike 發明 。每個文字符號用 1 - 4 個字節表示,ASCII 字符編碼占 1 字節,與傳統 ASCII 碼一致 ;若最高位是 110,編碼占 2 個字節;若最高位是 1110,編碼占 3 個字節;若最高位是 11110,編碼占 4 個字節 。
編碼特性
- 緊湊兼容:緊湊且兼容 ASCII,從左向右解碼不超過 3 字節就能定位一個字符,能快速搜索字符,無需考慮前文,字符順序與 Unicode 碼點順序一致,編碼本身不會嵌入 NUL 字節 。
- 操作便利:基于 UTF - 8 編碼的字符串操作無需解碼即可進行,如判斷前綴(
HasPrefix
函數 )、后綴(HasSuffix
函數 )、包含子串(Contains
函數 )等 。
轉義與碼點表示
Unicode 轉義符可用于文字符號,碼點值小于 256 的可寫成單個十六進制數轉義形式,更高碼點需用\u
或\U
轉義 。不同轉義序列形式的字符串字面量,實質字符串值相同 。
字符串操作與解碼
- 統計與遍歷:可使用
unicode/utf8
包中的函數,如RuneCountInString
統計字符串中文字符號數目 。通過for i, r := range s
循環可隱式解碼遍歷 UTF - 8 編碼字符串,對于非 ASCII 文字符號,下標增量大于 1 。 - 顯式解碼:
utf8.DecodeRuneInString
函數可返回文字符號本身和其按 UTF - 8 編碼所占字節數 ,用于顯式解碼操作 。
類型轉換相關
[]rune
轉換用于 UTF - 8 編碼字符串時,返回其 Unicode 碼點序列 。- 將文字符號類型的
slice
轉換成字符串,會輸出各文字符號的 UTF - 8 編碼拼接結果 。 - 整數轉換為字符串時,按文字符號類型解讀,產生代表該文字符號值的 UTF - 8 編碼 。
字符串和字節 slice
標準包功能
- strings 包:提供字符串搜索、替換、比較、修整、切分與連接等操作函數 。
- bytes 包:功能類似 strings 包,用于操作字節 slice(
[]byte
),且提供Buffer
類型,能高效處理字符串構建,避免多次內存分配和復制 。 - strconv 包:用于布爾值、整數、浮點數與字符串間的類型轉換,以及字符串添加 / 去除引號等操作 。
- unicode 包:包含判別文字符號值特性(如是否為數字
IsDigit
、字母IsLetter
、大寫IsUpper
、小寫IsLower
)的函數,還有轉換大小寫(ToUpper
、ToLower
)的函數,遵循 Unicode 標準 。
函數示例
func main() {fmt.Println(basename2("a/b/c.go"))fmt.Println(basename2("c.d.go"))fmt.Println(basename2("abc"))
}func basename2(s string) string {slash := strings.LastIndex(s, "/")s = s[slash+1:]if dot := strings.LastIndex(s, "."); dot >= 0 {s = s[:dot]}return s
}func basename1(s string) string{for i := len(s) - 1; i >= 0; i-- {if s[i] == '/' {s = s[i + 1:]break;}}for i := len(s) - 1; i >= 0; i-- {if s[i] == '.'{s = s[:i]break}}return s
}
- basename 函數:有兩種實現方式,初版獨立完成工作,移除字符串中類似文件系統路徑的前綴和文件類型后綴 ;簡化版利用
strings.LastIndex
函數,更簡潔高效 。
字符串與字節 slice 轉換
- 字符串和字節 slice 可相互轉換,
[]byte(s)
將字符串s
轉換為字節 slice ,會分配新字節數組并拷貝內容;string(b)
將字節 sliceb
轉換為字符串,會生成副本 。strings 包和 bytes 包有功能對應的實用函數,只是操作對象分別為字符串和字節 slice 。
func main() {fmt.Println(intsToString([]int{1, 2, 3}))
}func intsToString(values []int) string {var buf bytes.Bufferbuf.WriteByte('[')for i, v := range values {if i > 0 {buf.WriteString(", ")}fmt.Fprintf(&buf, "%d", v)}buf.WriteByte(']')return buf.String()
}
- intsToString 函數:將字節 slice 轉化為 string。
字符串和數字的相互轉換
整數轉字符串
- 可使用
fmt.Sprintf
函數,通過格式化謂詞(如%d
)將整數轉換為字符串,例如x := 123; y := fmt.Sprintf("%d", x)
。 - 也可使用
strconv.Itoa
函數,它專門用于將整數轉換為 ASCII 字符串 ,如strconv.Itoa(x)
。 strconv.FormatInt
和strconv.FormatUint
函數可按不同進位制格式化數字 ,如strconv.FormatInt(int64(x), 2)
可將整數按二進制格式輸出 。相比之下,fmt.Printf
的%b
、%d
、%o
、%x
等謂詞在包含額外信息時更方便 。
字符串轉整數
strconv.Atoi
函數用于將表示整數的字符串轉換為整型 ,如x, err := strconv.Atoi("123")
。strconv.ParseInt
函數可指定進制和結果匹配的整型大小(第三個參數 ),如y, err := strconv.ParseInt("123", 10, 64)
,結果類型為int64
,可再轉換為較小類型 。strconv.ParseUint
用于無符號整數轉換 。
輸入處理
- 對于字符串和數字混合的單行輸入,可嘗試用
fmt.Scanf
解釋 ,但它在處理不完整或不規則輸入時靈活性欠佳 。
常量
- 定義:常量是在編譯階段就能計算出值的表達式,本質屬于基本類型(布爾型、字符串、數字 ) 。其聲明類似變量,但值恒定,防止程序運行中被意外修改,適合表示數學常量(如圓周率
pi
) 。 - 計算時機:許多常量計算在編譯時完成,減少運行時工作量,利于編譯器優化 。操作數為常量時,一些運行時才報錯的情況(如整數除 0 )編譯時就會報錯 。常量參與的數學、邏輯、比較運算結果仍是常量,類型轉換結果和部分內置函數(
len
、cap
等 )返回值也是常量 。
聲明與使用
- 單個常量聲明:用
const
關鍵字,如const pi = 3.14159
。 - 多個常量聲明:可在一個
const
聲明中定義一系列常量,適用于相關值,如const ( e = 2.71828… pi = 3.14159… )
。 - 在類型聲明中使用:常量表達式可用于數組類型長度聲明,如
const IPv4Len = 4; var p [IPv4Len]byte
。 - 類型推斷:常量聲明可指定類型和值,未顯式指定類型時,根據右邊表達式推斷 ,如
const noDelay time.Duration = 0
。 - 復用表達式:同時聲明一組常量時,除第一項外,其他項等號右側表達式可省略,復用前面一項的表達式及其類型 。
常量生成器 iota
iota
是常量生成器,用于創建一系列相關值,在常量聲明中,它從 0 開始取值,逐項加 1 。
應用示例
type Weekday int
const (Sunday Weekday = iotaMondayTuesdayWednesdayThursdayFridaySaturday
)
- 枚舉類型定義:以
time
包中Weekday
類型定義為例,聲明每周 7 天為Weekday
類型常量,從Sunday
開始,Sunday
值為 0 ,Monday
值為 1 ,依此類推 。
type Flags uint
cosnt (FlagUp Flags = 1 << itoaFlagBroadcastFlagLoopbackFlagPointToPointFlagMulticast
)func IsUp(v Flags) bool { return v&FlagUp == FlagUp }
func TurnDown(v *Flags) { *v &^= FlagUp }
func SetBroadcast(v *Flags) { *v |= FlagBroadcast }
func IsCast(v Flags) bool { return v&(FlagBroadcast|FlagMulticast) != 0}
- 位標志定義:借助
net
包代碼,定義Flags
類型常量,如FlagUp = 1 << iota
,隨著iota
遞增,每個常量按1 << iota
賦值,等價于 2 的連續次冪,用于表示不同的位標志,如FlagUp
(向上 )、FlagBroadcast
(支持廣播訪問 )等 ,還有相關函數用于判定、設置或清除這些位標志 。
const (_ = 1 << (10 * itoa)KiBMiBGiBTiBPiBEiBZiBYiB
)
- 冪值定義:聲明表示 1024 的冪的常量,如
const { _ = 1 << (10 * iota); KiB; MiB; … }
,iota
遞增,對應值為 1024 的不同冪次 。
局限性
- 由于 Go 語言不存在指數運算符,
iota
無法直接生成 1000 的冪(如KB
、MB
) 。
無類型常量
- Go 語言中許多常量不從屬具體類型,編譯器將其表示為精度更高的值(算術精度可達 256 位 ),有 6 種無類型常量,即無類型布爾、無類型整數、無類型文字符號、無類型浮點數、無類型復數、無類型字符串 。
優勢
-
可暫時維持高精度,能用于更多表達式且無需轉換類型 。如計算中值過大無法用常規整型存儲的常量,可參與運算;
math.Pi
作為無類型常量可用于需浮點值或復數的地方,若一開始確定類型(如float64
),會導致精度下降 。 -
類型推斷:常量字面量類型由語法決定,如
0
(無類型整數 )、0.0
(無類型浮點數 )、0i
(無類型復數 )、'\u0000'
(無類型文字符號 ) 。常量除法中,操作數寫法影響結果類型(如整數除法結果可能是整型,浮點數除法結果是浮點型 ) 。 -
類型轉換:無類型常量聲明為變量或給變量賦值時,會隱式轉換成變量類型 。顯式或隱式轉換時,目標類型要能表示原值,實數和復數允許舍入取整 。變量聲明未顯式指定類型時,無類型常量會隱式轉換為變量默認類型 。無類型整數可轉成
int
,無類型浮點數和復數分別轉成float64
和complex128
。要將變量轉成不同類型,需顯式轉換無類型常量或在聲明時指明類型 。
接口值與默認類型
- 將無類型常量轉換為接口值時,其默認類型決定接口值動態類型,如
fmt.Printf("%T\n", 0)
輸出int
,fmt.Printf("%T\n", 0.0)
輸出float64
等 。
浮點型 ) 。
- 類型轉換:無類型常量聲明為變量或給變量賦值時,會隱式轉換成變量類型 。顯式或隱式轉換時,目標類型要能表示原值,實數和復數允許舍入取整 。變量聲明未顯式指定類型時,無類型常量會隱式轉換為變量默認類型 。無類型整數可轉成
int
,無類型浮點數和復數分別轉成float64
和complex128
。要將變量轉成不同類型,需顯式轉換無類型常量或在聲明時指明類型 。
接口值與默認類型
- 將無類型常量轉換為接口值時,其默認類型決定接口值動態類型,如
fmt.Printf("%T\n", 0)
輸出int
,fmt.Printf("%T\n", 0.0)
輸出float64
等 。
參考資料:《Go程序設計語言》