入門學(xué)習(xí)Go的基本語法
1. 變量與常量
Golang 中的標(biāo)識符與關(guān)鍵字
標(biāo)識符
Go語言中標(biāo)識符由字母數(shù)字和_(下劃線)組成,并且只能以字母和_開頭。 舉幾個例子:abc, _, _123, a123
。
關(guān)鍵字
關(guān)鍵字和保留字都不建議用作變量名:
Go語言中有25個關(guān)鍵字:
break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var
此外,Go語言中還有37個保留字。
Constants: true false iota nil Types: int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr float32 float64 complex128 complex64 bool byte rune string error Functions: make len cap new append copy close delete complex real imag panic recover
Golang 中的變量
Go語言中的每一個變量都有自己的類型,并且變量必須經(jīng)過聲明才能開始使用,同一作用域內(nèi)不支持重復(fù)聲明。 并且Go語言的變量聲明后必須使用。
標(biāo)準(zhǔn)聲明
Go語言的變量聲明格式為:(Golang中變量的聲明推薦駝峰式命名法)
變量聲明以關(guān)鍵字var
開頭,變量類型放在變量的后面,行尾無需分號。 舉個例子:
var 變量名 變量類型
批量聲明
每聲明一個變量就需要寫var
關(guān)鍵字會比較繁瑣,go語言中還支持批量變量聲明:
var name string var age int var flag bool
變量的初始化
Go語言在聲明變量的時候,會自動對變量對應(yīng)的內(nèi)存區(qū)域進行初始化操作。每個變量會被初始化成其類型的默認(rèn)值,例如: 整型和浮點型變量的默認(rèn)值為0
。 字符串變量的默認(rèn)值為空字符串
。 布爾型變量默認(rèn)為false
。 切片、函數(shù)、指針變量的默認(rèn)為nil
。
當(dāng)然我們也可在聲明變量的時候為其指定初始值。變量初始化的標(biāo)準(zhǔn)格式如下:
var 變量名 類型 = 表達式
舉個例子:
var name string = "csp" var age int = 22
或者一次初始化多個變量
var name, age = "csp", 22
類型推導(dǎo)(根據(jù)值自動判斷變量的類型)
有時候我們會將變量的類型省略,這個時候編譯器會根據(jù)等號右邊的值來推導(dǎo)變量的類型完成初始化。
var name = "csp" //自動識別為string var age = 18 //自動識別為int
短變量聲明
在函數(shù)內(nèi)部,可以使用更簡略的 :=
方式聲明并初始化變量。
package main import "fmt" // 全局變量m var m = 100 func main() { n := 10 m := 200 // 此處聲明局部變量m fmt.Println(m, n) }
匿名變量
在使用多重賦值時,如果想要忽略某個值,可以使用匿名變量(anonymous variable)。
匿名變量用一個下劃線_表示,例如:
func foo() (int, string) { return 10, "csp" } func main() { x, _ := foo() //只接收foo 函數(shù)的第一個返回值 _, y := foo() //只接收foo 函數(shù)的第二個返回值 fmt.Println("x=", x) fmt.Println("y=", y) }
匿名變量不占用命名空間,不會分配內(nèi)存,所以匿名變量之間不存在重復(fù)聲明。 (在Lua
等編程語言里,匿名變量也被叫做啞元變量。)
注意事項:
- 函數(shù)外的每個語句都必須以關(guān)鍵字開始(var、const、func等)
:=
不能使用在函數(shù)外。_
多用于占位,表示忽略值。
Golang 中的常量
相對于變量,常量是恒定不變的值,多用于定義程序運行期間不會改變的那些值。 常量的聲明和變量聲明非常類似,只是把var
換成了const
,常量在定義的時候必須賦值。
const pi = 3.1415 const e = 2.7182
聲明了pi和e這兩個常量之后,在整個程序運行期間它們的值都不能再發(fā)生變化了。
多個常量也可以一起聲明:
const ( pi = 3.1415 e = 2.7182 )
const同時聲明多個常量時,如果省略了值則表示和上面一行的值相同。 例如:
const ( n1 = 100 n2 n3 )
上面示例中,常量n1、n2、n3
的值都是100。
Golang 中的iota常量計數(shù)器
iota
是go語言的常量計數(shù)器,只能在常量的表達式中使用。
iota
在const關(guān)鍵字出現(xiàn)時將被重置為0。const中每新增一行常量聲明將使iota
計數(shù)累加一次(iota可理解為const語句塊中的行索引)。 使用iota能簡化定義,在定義枚舉時很有用。
舉個例子:
const ( n1 = iota //0 n2 //1 n3 //2 n4 //3 )
幾個常見的
iota
示例
使用_
跳過某些值
const ( n1 = iota //0 n2 //1 _ n4 //3 )
iota
聲明中間插隊
const ( n1 = iota //0 n2 = 100 //100 n3 = iota //2 n4 //3 ) const n5 = iota //0
定義數(shù)量級 (這里的<<
表示左移操作,1<<10
表示將1的二進制表示向左移10位,也就是由1
變成了10000000000
,也就是十進制的1024。同理2<<2
表示將2的二進制表示向左移2位,也就是由10
變成了1000
,也就是十進制的8。)
const ( _ = iota KB = 1 << (10 * iota)// 1 左移動 10 位 == 2^10 == 1024B = 1KB MB = 1 << (10 * iota)// 在原來基礎(chǔ)上再左移動10位,2^20 == 1MB GB = 1 << (10 * iota) TB = 1 << (10 * iota) PB = 1 << (10 * iota) )
多個iota
定義在一行
const ( a, b = iota + 1, iota + 2 //1,2 c, d //2,3 e, f //3,4 )
2. 基本數(shù)據(jù)類型
Golang 中的整型
整型分為以下兩個大類:
按長度分為:int8、int16、int32、int64
對應(yīng)的無符號整型:uint8、uint16、uint32、uint64
其中,uint8
就是我們熟知的byte
型,int16
對應(yīng)C語言中的short
型,int64對應(yīng)C語言中的long
型。
類型 | 描述 |
---|---|
uint8 | 無符號 8位整型 (0 到 255) |
uint16 | 無符號 16位整型 (0 到 65535) |
uint32 | 無符號 32位整型 (0 到 4294967295) |
uint64 | 無符號 64位整型 (0 到 18446744073709551615) |
int8 | 有符號 8位整型 (-128 到 127) |
int16 | 有符號 16位整型 (-32768 到 32767) |
int32 | 有符號 32位整型 (-2147483648 到 2147483647) |
int64 | 有符號 64位整型 (-9223372036854775808 到 9223372036854775807) |
特殊整型
類型 | 描述 |
---|---|
uint | 32位操作系統(tǒng)上就是uint32,64位操作系統(tǒng)上就是uint64 |
int | 32位操作系統(tǒng)上就是int32,64位操作系統(tǒng)上就是int64 |
uintptr | 無符號整型,用于存放一個指針 |
注意: 在使用int
和 uint
類型時,不能假定它是32位或64位的整型,而是考慮int和uint可能在不同平臺上的差異。
注意事項 獲取對象的長度的內(nèi)建len()
函數(shù)返回的長度可以根據(jù)不同平臺的字節(jié)長度進行變化。實際使用中,切片或 map 的元素數(shù)量等都可以用int
來表示。在涉及到二進制傳輸、讀寫文件的結(jié)構(gòu)描述時,為了保持文件的結(jié)構(gòu)不會受到不同編譯目標(biāo)平臺字節(jié)長度的影響,不要使用int
和 uint
。
數(shù)字進制的表示
Go1.13版本之后引入了數(shù)字字面量語法,這樣便于開發(fā)者以二進制、八進制或十六進制浮點數(shù)的格式定義數(shù)字,例如:
v := 0b00101101
, 代表二進制的 101101,相當(dāng)于十進制的 45。 v := 0o377
,代表八進制的 377,相當(dāng)于十進制的 255。 v := 0x1p-2
,代表十六進制的 1 除以 2²,也就是 0.25。
而且還允許我們用 _
來分隔數(shù)字,比如說: v := 123_456
表示 v 的值等于 123456。
我們可以借助fmt函數(shù)來將一個整數(shù)以不同進制形式展示。
package main import "fmt" func main(){ // 十進制 var a int = 10 fmt.Printf("%d \n", a) // 10 fmt.Printf("%b \n", a) // 1010 占位符%b表示二進制 // 八進制 以0開頭 var b int = 077 fmt.Printf("%o \n", b) // 77 // 十六進制 以0x開頭 var c int = 0xff fmt.Printf("%x \n", c) // ff fmt.Printf("%X \n", c) // FF }
Golang 中的浮點型
Go語言支持兩種浮點型數(shù):float32
和float64
(默認(rèn))。這兩種浮點型數(shù)據(jù)格式遵循IEEE 754
標(biāo)準(zhǔn): float32
的浮點數(shù)的最大范圍約為 3.4e38
,可以使用常量定義:math.MaxFloat32
。 float64
的浮點數(shù)的最大范圍約為 1.8e308
,可以使用一個常量定義:math.MaxFloat64
。
打印浮點數(shù)時,可以使用fmt
包配合動詞%f
,代碼如下:
package main import ( "fmt" "math" ) func main() { fmt.Printf("%f\n", math.Pi) fmt.Printf("%.2f\n", math.Pi) }
Golang 中的復(fù)數(shù)
complex64和complex128
var c1 complex64 c1 = 1 + 2i var c2 complex128 c2 = 2 + 3i fmt.Println(c1) fmt.Println(c2)
復(fù)數(shù)有實部和虛部,complex64的實部和虛部為32位,complex128的實部和虛部為64位。
Golang 中的布爾值
Go語言中以bool
類型進行聲明布爾型數(shù)據(jù),布爾型數(shù)據(jù)只有true(真)
和false(假)
兩個值。
注意:
布爾類型變量的默認(rèn)值為false
。
Go 語言中不允許將整型強制轉(zhuǎn)換為布爾型.
布爾型無法參與數(shù)值運算,也無法與其他類型進行轉(zhuǎn)換。
Golang 中的字符串
Go語言中的字符串以原生數(shù)據(jù)類型出現(xiàn),使用字符串就像使用其他原生數(shù)據(jù)類型(int、bool、float32、float64 等)一樣。 Go 語言里的字符串的內(nèi)部實現(xiàn)使用UTF-8
編碼。 字符串的值為雙引號(")
中的內(nèi)容,可以在Go語言的源碼中直接添加非ASCII碼字符,例如:
s1 := "hello" s2 := "你好"
字符串轉(zhuǎn)義符
Go 語言的字符串常見轉(zhuǎn)義符包含回車、換行、單雙引號、制表符等,如下表所示。
轉(zhuǎn)義符 | 含義 |
---|---|
\r | 回車符(返回行首) |
\n | 換行符(直接跳到下一行的同列位置) |
\t | 制表符 |
\' | 單引號 |
\" | 雙引號 |
\\ | 反斜杠 |
舉個例子,我們要打印一個Windows平臺下的一個文件路徑:
package main import ( "fmt" ) func main() { fmt.Println("str := \"c:\\Code\\hello_golang\\go.exe\"") }
多行字符串
Go語言中要定義一個多行字符串時,就必須使用反引號
字符:
s1 := `第一行 第二行 第三行 ` fmt.Println(s1)
反引號間換行將被作為字符串中的換行,但是所有的轉(zhuǎn)義字符均無效,文本將會原樣輸出。
字符串的常用操作
方法 | 介紹 |
---|---|
len(str) | 求字符串長度 |
+或fmt.Sprintf | 拼接字符串 |
strings.Split | 分割 |
strings.contains | 判斷是否包含 |
strings.HasPrefix,strings.HasSuffix | 前綴/后綴判斷 |
strings.Index(),strings.LastIndex() | 子串出現(xiàn)的位置 |
strings.Join(a[]string, sep string) | join操作 |
Golang 中的byte和rune類型
組成每個字符串的元素叫做“字符”,可以通過遍歷或者單個獲取字符串元素獲得字符。 字符用單引號(')包裹起來,如:
var a := '中' var b := 'x'
Go 語言的字符有以下兩種:
uint8
類型,或者叫byte
型,代表了ASCII
碼的一個字符。rune
類型,代表一個UTF-8字符
。
當(dāng)需要處理中文、日文或者其他復(fù)合字符時,則需要用到rune
類型。rune
類型實際是一個int32
。
Go 使用了特殊的 rune 類型來處理 Unicode,讓基于 Unicode 的文本處理更為方便,也可以使用 byte 型進行默認(rèn)字符串處理,性能和擴展性都有照顧。
// 遍歷字符串 func traversalString() { s := "hello沙河" for i := 0; i < len(s); i++ { //byte fmt.Printf("%v(%c) ", s[i], s[i]) } fmt.Println() for _, r := range s { //rune fmt.Printf("%v(%c) ", r, r) } fmt.Println() }
輸出:
104(h) 101(e) 108(l) 108(l) 111(o) 230(æ) 178(²) 153() 230(æ) 178(²) 179(³) 104(h) 101(e) 108(l) 108(l) 111(o) 27801(沙) 27827(河)
因為UTF8編碼下一個中文漢字由3~4個字節(jié)組成,所以我們不能簡單的按照字節(jié)去遍歷一個包含中文的字符串,否則就會出現(xiàn)上面輸出中第一行的結(jié)果。
字符串底層是一個byte數(shù)組,所以可以和[]byte
類型相互轉(zhuǎn)換。字符串是不能修改的 字符串是由byte字節(jié)組成,所以字符串的長度是byte字節(jié)的長度。 rune類型用來表示utf8字符,一個rune字符由一個或多個byte組成。
修改字符串
要修改字符串,需要先將其轉(zhuǎn)換成[]rune
或[]byte
,完成后再轉(zhuǎn)換為string
。無論哪種轉(zhuǎn)換,都會重新分配內(nèi)存,并復(fù)制字節(jié)數(shù)組。
func changeString() { s1 := "big" // 強制類型轉(zhuǎn)換 byteS1 := []byte(s1) byteS1[0] = 'p' fmt.Println(string(byteS1)) s2 := "白蘿卜" runeS2 := []rune(s2) runeS2[0] = '紅' fmt.Println(string(runeS2)) }
Golang 中的類型轉(zhuǎn)換
Go語言中只有強制類型轉(zhuǎn)換,沒有隱式類型轉(zhuǎn)換。該語法只能在兩個類型之間支持相互轉(zhuǎn)換的時候使用。
強制類型轉(zhuǎn)換的基本語法如下:
T(表達式)
其中,T表示要轉(zhuǎn)換的類型。表達式包括變量、復(fù)雜算子和函數(shù)返回值等.
比如計算直角三角形的斜邊長時使用math包的Sqrt()函數(shù),該函數(shù)接收的是float64類型的參數(shù),而變量a和b都是int類型的,這個時候就需要將a和b強制類型轉(zhuǎn)換為float64類型。
func sqrtDemo() { var a, b = 3, 4 var c int // math.Sqrt()接收的參數(shù)是float64類型,需要強制轉(zhuǎn)換 c = int(math.Sqrt(float64(a*a + b*b))) fmt.Println(c) }
練習(xí)題
- 編寫代碼分別定義一個整型、浮點型、布爾型、字符串型變量,使用
fmt.Printf()
搭配%T
分別打印出上述變量的值和類型。 - 編寫代碼統(tǒng)計出字符串"
hello沙河小王子
"中漢字的數(shù)量。
3. if 判斷和 for 循環(huán)
Go語言中最常用的流程控制有if
和for
,而switch
和goto
主要是為了簡化代碼、降低重復(fù)代碼而生的結(jié)構(gòu),屬于擴展類的流程控制。
if else(分支結(jié)構(gòu))
if 條件判斷基本寫法
Go語言中if條件判斷的格式如下:
if 表達式1 { 分支1 } else if 表達式2 { 分支2 } else{ 分支3 }
當(dāng)表達式1的結(jié)果為true
時,執(zhí)行分支1,否則判斷表達式2,如果滿足則執(zhí)行分支2,都不滿足時,則執(zhí)行分支3。 if判斷中的else if
和else
都是可選的,可以根據(jù)實際需要進行選擇。
Go語言規(guī)定與if
匹配的左括號{
必須與if和表達式
放在同一行,{
放在其他位置會觸發(fā)編譯錯誤。 同理,與else
匹配的{也必須與else
寫在同一行,else
也必須與上一個if
或else if
右邊的大括號在同一行。
舉個例子:
func ifDemo1() { score := 65 if score >= 90 { fmt.Println("A") } else if score > 75 { fmt.Println("B") } else { fmt.Println("C") } }
if 條件判斷特殊寫法
if條件判斷還有一種特殊的寫法,可以在 if 表達式之前添加一個執(zhí)行語句,再根據(jù)變量值進行判斷,舉個例子:
func ifDemo2() { if score := 65; score >= 90 { fmt.Println("A") } else if score > 75 { fmt.Println("B") } else { fmt.Println("C") } }
思考題: 上下兩種寫法的區(qū)別在哪里?
for(循環(huán)結(jié)構(gòu))
Go 語言中的所有循環(huán)類型均可以使用for關(guān)鍵字來完成。
for循環(huán)的基本格式如下:
for 初始語句;條件表達式;結(jié)束語句{ 循環(huán)體語句 }
條件表達式返回true時循環(huán)體不停地進行循環(huán),直到條件表達式返回false時自動退出循環(huán)。
func forDemo() { for i := 0; i < 10; i++ { fmt.Println(i) } }
for循環(huán)的初始語句可以被忽略,但是初始語句后的分號必須要寫,例如:
func forDemo2() { i := 0 for ; i < 10; i++ { fmt.Println(i) } }
for循環(huán)的初始語句和結(jié)束語句都可以省略,例如:
func forDemo2() { i := 0 for ; i < 10; i++ { fmt.Println(i) } }
這種寫法類似于其他編程語言中的while,在while后添加一個條件表達式,滿足條件表達式時持續(xù)循環(huán),否則結(jié)束循環(huán)。
無限循環(huán)
for { 循環(huán)體語句 }
for循環(huán)可以通過break、goto、return、panic
語句強制退出循環(huán)。
for range(鍵值循環(huán))
Go語言中可以使用for range
遍歷數(shù)組、切片、字符串、map 及通道(channel)。 通過for range
遍歷的返回值有以下規(guī)律:
數(shù)組、切片、字符串返回索引和值。map返回鍵和值。通道(channel)只返回通道內(nèi)的值。
s := "hello 海賊王" for i,v := range d { fmt.Printf("%d %c\n",i,v); } // 輸出結(jié)果 0 h 1 e 2 l 3 l 4 o 5 7 海 8 賊 9 王
switch case
使用switch
語句可方便地對大量的值進行條件判斷。
func switchDemo1() { finger := 3 switch finger { case 1: fmt.Println("大拇指") case 2: fmt.Println("食指") case 3: fmt.Println("中指") case 4: fmt.Println("無名指") case 5: fmt.Println("小拇指") default: fmt.Println("無效的輸入!") } }
Go語言規(guī)定每個switch
只能有一個default
分支。
一個分支可以有多個值,多個case值中間使用英文逗號分隔。
func testSwitch3() { switch n := 7; n { case 1, 3, 5, 7, 9: fmt.Println("奇數(shù)") case 2, 4, 6, 8: fmt.Println("偶數(shù)") default: fmt.Println(n) } }
分支還可以使用表達式,這時候switch語句后面不需要再跟判斷變量。例如:
func switchDemo4() { age := 30 switch { case age < 25: fmt.Println("好好學(xué)習(xí)吧") case age > 25 && age < 35: fmt.Println("好好工作吧") case age > 60: fmt.Println("好好享受吧") default: fmt.Println("活著真好") } }
fallthrough
語法可以執(zhí)行滿足條件的case的下一個case
,是為了兼容C語言中的case設(shè)計的。
func switchDemo5() { s := "a" switch { case s == "a": fmt.Println("a") fallthrough case s == "b": fmt.Println("b") case s == "c": fmt.Println("c") default: fmt.Println("...") } }
輸出:
a b
goto(跳轉(zhuǎn)到指定標(biāo)簽)
goto
語句通過標(biāo)簽進行代碼間的無條件跳轉(zhuǎn)。goto
語句可以在快速跳出循環(huán)、避免重復(fù)退出上有一定的幫助。Go語言中使用goto
語句能簡化一些代碼的實現(xiàn)過程。 例如雙層嵌套的for循環(huán)要退出時:
func gotoDemo1() { var breakFlag bool for i := 0; i < 10; i++ { for j := 0; j < 10; j++ { if j == 2 { // 設(shè)置退出標(biāo)簽 breakFlag = true break } fmt.Printf("%v-%v\n", i, j) } // 外層for循環(huán)判斷 if breakFlag { break } } }
使用goto
語句能簡化代碼:
func gotoDemo2() { for i := 0; i < 10; i++ { for j := 0; j < 10; j++ { if j == 2 { // 設(shè)置退出標(biāo)簽 goto breakTag } fmt.Printf("%v-%v\n", i, j) } } return // 標(biāo)簽 breakTag: fmt.Println("結(jié)束for循環(huán)") }
break(跳出循環(huán))
break
語句可以結(jié)束for、switch
和select
的代碼塊。
break
語句還可以在語句后面添加標(biāo)簽,表示退出某個標(biāo)簽對應(yīng)的代碼塊,標(biāo)簽要求必須定義在對應(yīng)的for、switch
和 select
的代碼塊上。 舉個例子:
func breakDemo1() { BREAKDEMO1: for i := 0; i < 10; i++ { for j := 0; j < 10; j++ { if j == 2 { break BREAKDEMO1 } fmt.Printf("%v-%v\n", i, j) } } fmt.Println("...") }
continue(繼續(xù)下次循環(huán))
continue
語句可以結(jié)束當(dāng)前循環(huán),開始下一次的循環(huán)迭代過程,僅限在for循環(huán)內(nèi)使用。
在 continue
語句后添加標(biāo)簽時,表示開始標(biāo)簽對應(yīng)的循環(huán)。例如:
func continueDemo() { forloop1: for i := 0; i < 5; i++ { // forloop2: for j := 0; j < 5; j++ { if i == 2 && j == 2 { continue forloop1 } fmt.Printf("%v-%v\n", i, j) } } }
總結(jié)
本篇文章就到這里了,希望能幫助到你,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
通過Go channel批量讀取數(shù)據(jù)的示例詳解
批量處理的主要邏輯是:從 channel 中接收數(shù)據(jù),積累到一定數(shù)量或者達到時間限制后,將數(shù)據(jù)批量處理(例如發(fā)送到 Kafka 或者寫入網(wǎng)絡(luò)),下面我將展示一個從 Go channel 中批量讀取數(shù)據(jù),并批量發(fā)送到 Kafka 和批量寫入網(wǎng)絡(luò)數(shù)據(jù)的示例,需要的朋友可以參考下2024-10-10Golang http包構(gòu)建RESTful API的實現(xiàn)
在Go語言中實現(xiàn)RESTful API可以利用標(biāo)準(zhǔn)庫net/http提供的功能,它允許你輕松地創(chuàng)建和處理HTTP請求,本文主要介紹了Golang http包構(gòu)建RESTful API的實現(xiàn),感興趣的可以了解一下2024-01-01詳解如何使用go-acme/lego實現(xiàn)自動簽發(fā)證書
這篇文章主要為大家詳細介紹了如何使用?go-acme/lego?的客戶端或庫完成證書的自動簽發(fā),文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03