所有go源碼以.go結尾
-
標識符以字母或下劃線開頭邑遏,大小寫敏感,(_是特殊標識符棍苹,還可用來忽略結果)
Go語言中的函數名无宿、變量名茵汰、常量名枢里、類型名、語句標號和包名等所有的命名,都遵循一個簡單的命名規(guī)則:一個名字必須以一個字母(Unicode字母)或下劃線開頭栏豺,后面可以跟任意數量的字母彬碱、數字或下劃線。大寫字母和小寫字母是不同的:heapSort和Heapsort是兩個不同的名字奥洼。
image.png -
GO有25個保留關鍵字
image.png 此外巷疼,還有大約30多個預定義的名字,比如int和true等灵奖,主要對應內建的常量嚼沿、類型和函數。
內建常量:
true false iota nil
內建類型:
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64 uintptr
bool byte rune string error
float32 float64 complex128 complex64
內建函數:
make len cap new append copy
real imag panic close delete recover complex
GO程序的一般結構
- Go程序是通過package來組織的瓷患,只有package名稱為main的包可以包含main函數骡尽,一個可執(zhí)行的程序,有且只有一個main包
- 任何一個代碼文件隸屬于一個包
- 通過import 關鍵字來導入其它非main包
比如:import {
"fmt"
"os"
} - 同一個包中函數擅编,直接調用
- 不同包中函數攀细,通過包名+
.
+ 函數名調用 - 包訪問權限規(guī)則:
a. 函數名首字符大寫即為 public
b. 函數名首字符小寫即為 private ,包外包不能訪問
GO的一些常用聲明
-
const
:定義常量
1.1 常量定義
const Pi float64 = 3.14
const zero = 0.0 // 浮點常量, 自動推導類型
const ( // 常量組
size int64 = 1024
eof = -1 // 整型常量, 自動推導類型
)
const u, v float32 = 0, 3 // u = 0.0, v = 3.0,常量的多重賦值
const a, b, c = 3, 4, "foo"
// a = 3, b = 4, c = "foo" //err, 常量不能修改
1.2 枚舉
常量聲明可以使用iota常量生成器初始化爱态,它用于生成一組以相似規(guī)則初始化的常量谭贪,但是不用每行都寫一遍初始化表達式
在一個const聲明語句中,在第一個聲明的常量所在的行锦担,iota將會被置為0俭识,然后再每一個有常量聲明的行加1
const (
x = iota // x == 0
y = iota // y == 1
z = iota // z == 2
w // 這里隱式地說w = iota,因此w == 3吆豹。其實上面y和z可同樣不用"= iota"
)
const v = iota // 每遇到一個const關鍵字鱼的,iota就會重置,此時v == 0
const (
h, i, j = iota, iota, iota //h=0,i=0,j=0 iota在同一行值相同
)
const (
a = iota //a=0
b = "B"
c = iota //c=2
d, e, f = iota, iota, iota //d=3,e=3,f=3
g = iota //g = 4
)
const (
x1 = iota * 10 // x1 == 0
y1 = iota * 10 // y1 == 10
z1 = iota * 10 // z1 == 20
)
-
var
:全局變量的聲明和賦值
2.1 變量聲明
var v1 int
var v2 int
//一次定義多個變量
var v3, v4 int
var (
v5 int
v6 int
)
2.2 變量初始化
var v1 int = 10 // 方式1
var v2 = 10 // 方式2痘煤,編譯器自動推導出v2的類型
v3 := 10 // 方式3凑阶,編譯器自動推導出v3的類型
fmt.Println("v3 type is ", reflect.TypeOf(v3)) //v3 type is int
//出現(xiàn)在 := 左側的變量不應該是已經被聲明過,:=定義時必須初始化
var v4 int
v4 := 2 //err
2.3 匿名變量
_(下劃線)是個特殊的變量名衷快,任何賦予它的值都會被丟棄:
_, i, _, j := 1, 2, 3, 4
func test() (int, string) {
return 250, "sb"
}
_, str := test()
-
type
:結構體和接口的聲明 -
func
:聲明函數func 函數名(參數列表)(返回值列表) { // 函數體 } // 可變參數 func add (arg... int){ // 0個或多個參數 } func add(a int,arg...int){// 1個或多個參數 } func add(a int,b int,arg ...int){// 2個或多個參數 } 注意:其中arg 是一個slice,我們可以通過arg[index]一次訪問所有參數宙橱,通過len(arg) 來判斷傳遞參數的個數
- GO的代碼注釋
/* 塊注釋 */
// 行注釋
命令行運行程序
基礎數據類型
GO語言內置以下這些基礎類型:
類型 | 名稱 | 長度 | 零值 | 說明 |
---|---|---|---|---|
bool | 布爾類型 | 1 | false | 其值不為真即為假,不可以用數字代表true或false |
byte | 字節(jié)型 | 1 | 0 | uint8 別名 |
rune | 字符類型 | 4 | 0 | 專用于存儲unicode編碼蘸拔,等價于uint32 |
int,uint | 整型 | 4或8 | 0 | 32位或64位 |
int8,uint8 | 整型 | 1 | 0 | -128~127 , 0 ~ 255 |
int16,uint16 | 整型 | 2 | 0 | -32768~32767, 0~65535 |
int32,uint32 | 整型 | 4 | 0 | -21億 ~ 21億 , 0 ~ 42億 |
int64,uint64 | 整型 | 8 | 0 | |
float32 | 浮點型 | 4 | 0.0 | 小數位精確到7位 |
floate64 | 浮點型 | 8 | 0.0 | 小數位精確到15位 |
complex64 | 復數類型 | 8 | ||
complex128 | 復數類型 | 16 | ||
uintptr | 整型 | 4或8 | 足以存儲指針的uint32或uint64整數 | |
string | 字符串 | "" | utf-8 字符串 | |
slice | 引用類型 | nil | ||
map | 引用類型 | nil | ||
chan | 引用類型 | nil |
布爾類型
var v1 bool
v1 = true
v2 := (1 == 2) // v2也會被推導為bool類型
//布爾類型不能接受其他類型的賦值师郑,不支持自動或強制的類型轉換
var b bool
b = 1 // err, 編譯錯誤
b = bool(1) // err, 編譯錯誤
整型
var v1 int32
v1 = 123
v2 := 64 // v1將會被自動推導為int類型
浮點型
var f1 float32
f1 = 12
f2 := 12.0 // 如果不加小數點, fvalue2會被推導為整型而不是浮點型调窍,float64
字符類型
package main
import (
"fmt"
)
func main() {
var ch1, ch2, ch3 byte
ch1 = 'a' //字符賦值
ch2 = 97 //字符的ascii碼賦值
ch3 = '\n' //轉義字符
fmt.Printf("ch1 = %c, ch2 = %c, %c", ch1, ch2, ch3)
}
字符串
var str string // 聲明一個字符串變量
str = "abc" // 字符串賦值
ch := str[0] // 取字符串的第一個字符
fmt.Printf("str = %s, len = %d\n", str, len(str)) //內置的函數len()來取字符串的長度
fmt.Printf("str[0] = %c, ch = %c\n", str[0], ch)
//`(反引號)括起的字符串為Raw字符串宝冕,即字符串在代碼中的形式就是打印時的形式,它沒有字符轉義邓萨,換行也將原樣輸出地梨。
str2 := `hello
mike \n \r測試
`
fmt.Println("str2 = ", str2)
/*
str2 = hello
mike \n \r測試
*/
復數類型
var v1 complex64 // 由2個float32構成的復數類型
v1 = 3.2 + 12i
v2 := 3.2 + 12i // v2是complex128類型
v3 := complex(3.2, 12) // v3結果同v2
fmt.Println(v1, v2, v3)
//內置函數real(v1)獲得該復數的實部
//通過imag(v1)獲得該復數的虛部
fmt.Println(real(v1), imag(v1))
包的格式化輸出輸入
格式說明
格式 | 含義 |
---|---|
%% | 一個%字面 |
%b | 一個二進制整數值(基數為2)菊卷,或者是一個(高級的)用科學計數法標識的指數為2的浮點數 |
%c | 字符型”ζ剩可以把輸入的數字按照ASCII碼相應轉換為對應的字符 |
%d | 一個十進制數值(基數為10) |
%e | 以科學記數法e 表示的浮點數或者復數值 |
%E | 以科學記數法E 表示的浮點數或者復數值 |
%f | 以標準記數法表示的浮點數或者復數值 |
%g | 以%e或者%f表示的浮點數或者復數洁闰,任何一個都以最為緊湊的方式輸出 |
%G | 以%E或者%f 表示的浮點數或者復數,任何一個都以最為緊湊的方式輸出 |
%o | 一個以八進制表示的數字(基數為8) |
%p | 以十六進制(基數為16)表示的一個值的地址万细,前綴為0x,字母使用小寫的a-f表示 |
%q | 使用Go語法以及必須時使用轉義扑眉,以雙引號括起來的字符串或者字節(jié)切片[]byte,或者是以單引號括起來的數字 |
%s | 字符串赖钞。輸出字符串中的字符直至字符串中的空字符(字符串以'\0‘結尾腰素,這個'\0'即空字符) |
%t | 以true或者false輸出的布爾值 |
%T | 使用Go語法輸出的值的類型 |
%U | 一個用Unicode表示法表示的整型碼點,默認值為4個數字字符 |
%v | 使用默認格式輸出的內置或者自定義類型的值雪营,或者是使用其類型的String()方式輸出的自定義值耸弄,如果該方法存在的話 |
%x | 以十六進制表示的整型值(基數為十六),數字a-f使用小寫表示 |
%X | 以十六進制表示的整型值(基數為十六)卓缰,數字A-F使用小寫表示 |
輸出
//整型
a := 15
fmt.Printf("a = %b\n", a) //a = 1111
fmt.Printf("%%\n") //只輸出一個%
//字符
ch := 'a'
fmt.Printf("ch = %c, %c\n", ch, 97) //a, a
//浮點型
f := 3.14
fmt.Printf("f = %f, %g\n", f, f) //f = 3.140000, 3.14
fmt.Printf("f type = %T\n", f) //f type = float64
//復數類型
v := complex(3.2, 12)
fmt.Printf("v = %f, %g\n", v, v) //v = (3.200000+12.000000i), (3.2+12i)
fmt.Printf("v type = %T\n", v) //v type = complex128
//布爾類型
fmt.Printf("%t, %t\n", true, false) //true, false
//字符串
str := "hello go"
fmt.Printf("str = %s\n", str) //str = hello go
輸入
var v int
fmt.Println("請輸入一個整型:")
fmt.Scanf("%d", &v)
//fmt.Scan(&v)
fmt.Println("v = ", v)
類型轉換
Go語言中不允許隱式轉換计呈,所有類型轉換必須顯式聲明,而且轉換只能發(fā)生在兩種相互兼容的類型之間征唬。
var ch byte = 97
//var a int = ch //err, cannot use ch (type byte) as type int in assignment
var a int = int(ch)
類型別名
type bigint int64 //int64類型改名為bigint
var x bigint = 100
type (
myint int //int改名為myint
mystr string //string改名為mystr
)
運算符
算數運算符
關系運算符
邏輯運算符
位運算符
賦值運算符
其它運算符
運算符優(yōu)先級
在Go語言中捌显,一元運算符擁有最高的優(yōu)先級,二元運算符的運算方向均是從左至右总寒。
下表列出了所有運算符以及它們的優(yōu)先級扶歪,由上至下代表優(yōu)先級由高到低:
流程控制
Go語言支持最基本的三種程序運行結構:順序結構、選擇結構摄闸、循環(huán)結構善镰。
? 順序結構:程序按順序執(zhí)行,不發(fā)生跳轉年枕。
? 選擇結構:依據是否滿足條件炫欺,有選擇的執(zhí)行相應功能。
? 循環(huán)結構:依據條件是否滿足熏兄,循環(huán)多次執(zhí)行某段代碼品洛。
- if語句
var a int = 3
if a == 3 { //條件表達式沒有括號
fmt.Println("a==3")
}
//支持一個初始化表達式, 初始化字句和條件表達式直接需要用分號分隔
if b := 3; b == 3 {
fmt.Println("b==3")
}
1.1 if...else 語句
if a := 3; a == 4 {
fmt.Println("a==4")
} else { //左大括號必須和條件語句或else在同一行
fmt.Println("a!=4")
}
1.2 if... else if ... else 語句
if a := 3; a > 3 {
fmt.Println("a>3")
} else if a < 3 {
fmt.Println("a<3")
} else if a == 3 {
fmt.Println("a==3")
} else {
fmt.Println("error")
}
- switch 語句
Go里面switch默認相當于每個case最后帶有break,匹配成功后不會自動向下執(zhí)行其他case摩桶,而是跳出整個switch, 但是可以使用fallthrough強制執(zhí)行后面的case代碼:
var score int = 90
switch score {
case 90:
fmt.Println("優(yōu)秀")
//fallthrough
case 80:
fmt.Println("良好")
//fallthrough
case 50, 60, 70:
fmt.Println("一般")
//fallthrough
default:
fmt.Println("差")
}
可以使用任何類型或表達式作為條件語句:
//1
switch s1 := 90; s1 { //初始化語句;條件
case 90:
fmt.Println("優(yōu)秀")
case 80:
fmt.Println("良好")
default:
fmt.Println("一般")
}
//2
var s2 int = 90
switch { //這里沒有寫條件
case s2 >= 90: //這里寫判斷語句
fmt.Println("優(yōu)秀")
case s2 >= 80:
fmt.Println("良好")
default:
fmt.Println("一般")
}
//3
switch s3 := 90; { //只有初始化語句桥状,沒有條件
case s3 >= 90: //這里寫判斷語句
fmt.Println("優(yōu)秀")
case s3 >= 80:
fmt.Println("良好")
default:
fmt.Println("一般")
}
- 循環(huán)語句
for語句
var i, sum int
for i = 1; i <= 100; i++ {
sum += i
}
fmt.Println("sum = ", sum)
range 語句
關鍵字 range 會返回兩個值,第一個返回值是元素的數組下標硝清,第二個返回值是元素的值:
s := "abc"
for i := range s { //支持 string/array/slice/map辅斟。
fmt.Printf("%c\n", s[i])
}
for _, c := range s { // 忽略 index
fmt.Printf("%c\n", c)
}
for i, c := range s {
fmt.Printf("%d, %c\n", i, c)
}
- 跳轉語句
break 和 continue
在循環(huán)里面有兩個關鍵操作break和continue,break操作是跳出當前循環(huán)芦拿,continue是跳過本次循環(huán)士飒。
for i := 0; i < 5; i++ {
if 2 == i {
//break //break操作是跳出當前循環(huán)
continue //continue是跳過本次循環(huán)
}
fmt.Println(i)
}
注意:break可?于for挽霉、switch、select变汪,?continue僅能?于for循環(huán)。
goto
用goto跳轉到必須在當前函數內定義的標簽:
func main() {
for i := 0; i < 5; i++ {
for {
fmt.Println(i)
goto LABEL //跳轉到標簽LABEL蚁趁,從標簽處裙盾,執(zhí)行代碼
}
}
fmt.Println("this is test")
LABEL:
fmt.Println("it is over")
}
函數
無參無返回值
func Test() { //無參無返回值函數定義
fmt.Println("this is a test func")
}
func main() {
Test() //無參無返回值函數調用
}
有參無返回值
普通參數列表
func Test01(v1 int, v2 int) { //方式1
fmt.Printf("v1 = %d, v2 = %d\n", v1, v2)
}
func Test02(v1, v2 int) { //方式2, v1, v2都是int類型
fmt.Printf("v1 = %d, v2 = %d\n", v1, v2)
}
func main() {
Test01(10, 20) //函數調用
Test02(11, 22) //函數調用
}
不定參數類型
不定參數是指函數傳入的參數個數為不定數量。為了做到這點他嫡,首先需要將函數定義為接受不定參數類型:
//形如...type格式的類型只能作為函數的參數類型存在番官,并且必須是最后一個參數
func Test(args ...int) {
for _, n := range args { //遍歷參數列表
fmt.Println(n)
}
}
func main() {
//函數調用,可傳0到多個參數
Test()
Test(1)
Test(1, 2, 3, 4)
}
不定參數的傳遞
func MyFunc01(args ...int) {
fmt.Println("MyFunc01")
for _, n := range args { //遍歷參數列表
fmt.Println(n)
}
}
func MyFunc02(args ...int) {
fmt.Println("MyFunc02")
for _, n := range args { //遍歷參數列表
fmt.Println(n)
}
}
func Test(args ...int) {
MyFunc01(args...) //按原樣傳遞, Test()的參數原封不動傳遞給MyFunc01
MyFunc02(args[1:]...) //Test()參數列表中钢属,第1個參數及以后的參數傳遞給MyFunc02
}
func main() {
Test(1, 2, 3) //函數調用
}
無參有返回值
有返回值的函數徘熔,必須有明確的終止語句,否則會引發(fā)編譯錯誤淆党。
一個返回值
func Test01() int { //方式1
return 250
}
//官方建議:最好命名返回值样漆,因為不命名返回值胧辽,雖然使得代碼更加簡潔了,但是會造成生成的文檔可讀性差
func Test02() (value int) { //方式2, 給返回值命名
value = 250
return value
}
func Test03() (value int) { //方式3, 給返回值命名
value = 250
return
}
func main() {
v1 := Test01() //函數調用
v2 := Test02() //函數調用
v3 := Test03() //函數調用
fmt.Printf("v1 = %d, v2 = %d, v3 = %d\n", v1, v2, v3)
}
多個返回值
func Test01() (int, string) { //方式1
return 250, "sb"
}
func Test02() (a int, str string) { //方式2, 給返回值命名
a = 250
str = "sb"
return
}
func main() {
v1, v2 := Test01() //函數調用
_, v3 := Test02() //函數調用, 第一個返回值丟棄
v4, _ := Test02() //函數調用侦香, 第二個返回值丟棄
fmt.Printf("v1 = %d, v2 = %s, v3 = %s, v4 = %d\n", v1, v2, v3, v4)
}
有參有返回值
//求2個數的最小值和最大值
func MinAndMax(num1 int, num2 int) (min int, max int) {
if num1 > num2 { //如果num1 大于 num2
min = num2
max = num1
} else {
max = num2
min = num1
}
return
}
func main() {
min, max := MinAndMax(33, 22)
fmt.Printf("min = %d, max = %d\n", min, max) //min = 22, max = 33
}
遞歸函數
遞歸指函數可以直接或間接的調用自身。
遞歸函數通常有相同的結構:一個跳出條件和一個遞歸體罐脊。所謂跳出條件就是根據傳入的參數判斷是否需要停止遞歸承绸,而遞歸體則是函數自身所做的一些處理。
//通過循環(huán)實現(xiàn)1+2+3……+100
func Test01() int {
i := 1
sum := 0
for i = 1; i <= 100; i++ {
sum += i
}
return sum
}
//通過遞歸實現(xiàn)1+2+3……+100
func Test02(num int) int {
if num == 1 {
return 1
}
return num + Test02(num-1) //函數調用本身
}
//通過遞歸實現(xiàn)1+2+3……+100
func Test03(num int) int {
if num == 100 {
return 100
}
return num + Test03(num+1) //函數調用本身
}
func main() {
fmt.Println(Test01()) //5050
fmt.Println(Test02(100)) //5050
fmt.Println(Test03(1)) //5050
}
函數類型
在Go語言中勒庄,函數也是一種數據類型串前,我們可以通過type來定義它,它的類型就是所有擁有相同的參數实蔽,相同的返回值的一種類型荡碾。
type FuncType func(int, int) int //聲明一個函數類型, func后面沒有函數名
//函數中有一個參數類型為函數類型:f FuncType
func Calc(a, b int, f FuncType) (result int) {
result = f(a, b) //通過調用f()實現(xiàn)任務
return
}
func Add(a, b int) int {
return a + b
}
func Minus(a, b int) int {
return a - b
}
func main() {
//函數調用,第三個參數為函數名字局装,此函數的參數玩荠,返回值必須和FuncType類型一致
result := Calc(1, 1, Add)
fmt.Println(result) //2
var f FuncType = Minus
fmt.Println("result = ", f(10, 2)) //result = 8
}
匿名函數與閉包
所謂閉包就是一個函數“捕獲”了和它在同一作用域的其它常量和變量,這就意味著當閉包被調用的時候贼邓,不管在程序什么地方調用阶冈,閉包能夠使用這些常量或者變量。