Golang基礎知多少
代碼結構概覽
首先,GO語言中的代碼結構做一個概覽
// 所屬包
package main
// 導入依賴包
import "fmt"
// 聲明常量
const filename = "abc.txt"
// 聲明全局變量
var a string = "hello"
// 類型聲明
type myint int
// 聲明結構體
type Student struct {
Name string
Age int
}
// 聲明接口
type learn interface {}
// 函數定義
func learnGo() {
fmt.Println("something good")
}
// main函數
func main() {
...
}
Package包
package是工程管理中依賴關係的體現:
- 每個Go語言源代碼開頭,都擁有一個package聲明,表示源碼文件所屬代碼包
- 如果要生成可執行文件,則必須要有名爲main的package包,並且該包下必須有main函數
- 相同路徑下只能存在一個package,一個package可以分多個源文件
Import導入
import語句用來導入所依賴的package包:
- 僅需要導入源文件中需要用到的package,存在不用的包導入,則會編譯報錯
- 導入語句的import可以一行行寫,也可以通過括號方式一起寫
- 如果一個main導入了其他的包,則將先順序導入依賴的包
- 導入過程包括初始化依賴包中的常量和變量等,如果有init()函數,則會自動執行
- 所有依賴的包導入完成後,纔會對main中的常量和變量進行初始化,然後執行main中的init()函數,最後執行main函數
此外,import語句還有以下幾種特殊寫法:
- 別名
//給fmt起別名爲f
import f "fmt"
//引用時則直接使用f
f.Println("Hello")
.
點標示
import (
. "fmt"
)
//點標示的包導入後,調用該包中的函數時,可以省略前綴包名
Println("Hello")
_
下劃線標示
//說明:使用下劃線標示後,表示只執行該包中的init函數,但並不通過包名來調用包中其他函數。此下劃線用法,往往是爲了註冊包裏面的引擎
import (
"log"
"net/http"
_ "net/http/pprof"
"os"
)
數據類型
數據類型是爲了把不同的數據分成不同的類型,以便在使用時僅分配類型對應所需內存大小。
基礎數據類型種類
與其他編程語言不一樣的是,golang原生支持複數類型:
- 整型
- uint8
- uint16
- uint32
- uint64
- int8
- int16
- int32
- int64
- int和uint: 32位或64位,取決於計算機類型
- 浮點型
- float32
- float64
- 複數
- complex64: 32位實數和虛數
- complex128: 64位實數和虛數
- 字符串
- string
- 布爾型
- bool
- 其他
- byte: 類似uint8
- rune: 類似int32
- uintptr: 無符號整型,用於存放一個指針
注意:
- go語言中沒有char,只有rune
- go語言中的類型轉換必須是顯式的,並且只能發生在兩種兼容類型之間
數據類型存儲大小
下面是在網上看到的一張描述各數據類型存儲大小的示例圖,畫的比較好,看了讓人覺得一目瞭然:
擴展數據類型
除了上面的基礎數據類型外,go語言中還有些適合複雜場景需求的特殊數據類型
- 指針類型
- 數組類型
- 切片類型
- 結構體類型
- Map類型
- 接口類型
- Channel類型
- …
變量
變量聲明和賦值可放在包內,或放在函數內。與其他編程語言最大的不同就是:變量類型寫在變量名後面
- 使用var關鍵字
var a string
a = "golang"
var b bool
var c, d int
var s1, s2 string = "hello", "world"
var (
x int
y float32
)
- 使用
:=
// 此種方式,沒有明確的寫出變量的類型,但是會根據右邊對應的賦值來識別類型
a, b, x, y, s1, s2 := true, false, 3, 3.14, "hello", "world"
注意:
- go語言中,聲明後的變量必須要使用,否則編譯報錯
- 全局變量的聲明必須採用var關鍵字方式
- 對於僅用作佔位而不後續使用的變量,可以使用
_
下劃線(常用在數組、map循環遍歷的場景) - 僅聲明但沒有賦值的變量,將使用類型零值來作爲默認值(如:整型默認0,布爾默認false,string默認空字符串)
- 大寫字母開頭的變量是可導出的公有變量;小寫字母開頭的變量是不可導出的私有變量
常量
常量的聲明
只有布爾類型,整、浮、複數類型,和字符串類型支持聲明爲常量。常量的聲明形式也分爲兩種:
- 顯式
聲明時指定了變量類型
const 變量名 變量類型 = 值
//例
const filename string = "hello.txt"
- 隱式
聲明時不指定變量類型,這種無類型常量會根據右邊賦的值來識別類型
const 變量名 變量類型 = 值
//例
const filename = "hello.txt"
const a, b = 3, 4
特殊常量iota
iota
在const關鍵字聲明出現時候的默認值爲0,之後是以步長1來按行遞增
注意:
- 出現在同一行的多個
iota
的值相等 iota
由0起始、按行遞增的作用範圍僅限於當前const關鍵字聲明的變量iota
可以做運算後再賦值,如:iota * 2
- 例1
const (
b = 1 << (10 * iota)
kb
mb
gb
tb
)
//上面示例的結果:b爲2的0次方,kb爲2的10次方,mb爲2的20次方,依次類推
- 例2
const (
a = iota
b = iota * 3
_ // 下劃線佔位符也用了一行,也會讓iota的值遞增
c = iota
)
const (
// 此const聲明中的iota仍然從0開始,不會受到上一個const聲明中的iota遞增的影響
d = iota * 2
e = iota
f = iota
)
const (
aa, bb = iota, iota * 3 // 出現在同一行的多個`iota`的值相等
cc, dd
_, _ // 佔位符的格式要與緊挨着的上一行的變量個數保持一致
ee = iota
_
ff
)
func main() {
fmt.Println("a", a)
fmt.Println("b", b)
fmt.Println("c", c)
fmt.Println("d", d)
fmt.Println("e", e)
fmt.Println("f", f)
fmt.Println("aa", aa)
fmt.Println("bb", bb)
fmt.Println("cc", cc)
fmt.Println("dd", dd)
fmt.Println("ee", ee)
fmt.Println("ff", ff)
}
// 執行結果:
// a 0
// b 3
// c 3
// d 0
// e 1
// f 2
// aa 0
// bb 0
// cc 1
// dd 3
// ee 3
// ff 5
運算符
算術運算符
+ - * / % ++ --
關係運算符
== != > < >= <=
邏輯運算符
&& || !
按位運算符
& | ^ << >>
賦值運算符
除了=
等號以外,算術運算符或按位運算符寫在等號左邊就可以變成一個新的賦值運算符,如:+= %= &= >>=
控制語句
if條件語句
語法格式
if [賦值表達式;] 條件語句1 {
...
} else if 條件語句2 {
...
} else {
...
}
注意:
- if條件裏不需要括號
- if條件裏可以賦值
- if條件裏賦值的變量的作用域僅限在這個if語句
例1: if
// 條件語句不需要括號
if num > 100 {
return 100
} else if num < 0 {
return 0
} else {
return num
}
// 帶賦值的條件語句
if contents, err := ioutil, ReadFile(filename); err == nil {
fmt.Println(string(contents))
} else {
fmt.Println("read file error: ", err)
}
switch選擇語句
語法格式
switch [表達式] {
case sth1:
...
case sth2:
...
default:
...
}
注意:
- switch關鍵字後面可以沒有表達式
- 在匹配到case後會自動break,除非使用fallthrough
- go語言中還有個select語句與switch非常相似,但是select只用於chan
例2: switch
// 判斷op爲哪種運算符
switch op {
case "+":
result = 1 + 1
case "-":
result = 1 - 1
case "*":
result = 1 * 1
case "/":
result = 1 / 1
default:
panic("wrong operator:" + op)
}
// switch關鍵字後沒有表達式的情況
var score int = 81
level := ""
switch {
case score < 60:
level = "F"
case score < 70:
level = "C"
case score < 80:
level = "B"
case score <= 100:
level = "A"
default:
panic(fmt.Sprintf("wrong socre: %d", score))
}
// 用type-switch的方式來判斷interface變量中實際存儲的變量類型
var a interface{}
a = 32
switch a.(type) {
case int:
fmt.Println("int")
case string:
fmt.Println("string")
default:
fmt.Println("something else")
}
for循環語句
語法格式
for 初始條件; 結束條件; 遞增表達式 {
…
}
注意:
- for的條件裏不需要括號
- for關鍵字後面的初始條件、結束條件、 遞增表達式都可以省略,此時相當於死循環
- go語言中沒有while;當省略初始條件時,就相當於其他語言中的while
例3: for
// 帶條件的常規for循環
sum := 0
for i := 1; i <= 100; i++ {
sum += i
}
// 死循環
for {
fmt.Println("hello world")
}
// 配合range進行遍歷
str := []string{"I", "am", "a", "boy"}
for key, value := range str {
fmt.Println("key: ", key , "value: ", value)
}
控制語句關鍵字
- goto
- break
- continue