Golang學(xué)習(xí) QQ群共同學(xué)習(xí)進(jìn)步成家立業(yè)工作 ^-^ 群號(hào):96933959
變量&常量
變量
變量名由字母、數(shù)字、下劃線組成,不能以數(shù)字開(kāi)頭。
...var ( A int //默認(rèn)為0 B string //默認(rèn)為"" C bool //默認(rèn)為false Name string = "suoning" Age = 18 // 自動(dòng)識(shí)別類型) func main() { sex := "man" //等價(jià)于 var sex string = "man" var girlfriend string //聲明變量 girlfriend = "Dawn" //變量賦值 Name := "Nick" //正確 //girlfriend := "Jenny" //錯(cuò)誤的!不能申明兩次 ... }
常量
常量使用const 修飾,代表永遠(yuǎn)是只讀的,不能修改。
常量中的數(shù)據(jù)類型只可以是布爾型、數(shù)字型(整數(shù)型、浮點(diǎn)型和復(fù)數(shù))和字符串型。
語(yǔ)法:const identifier [type] = value,其中type可以省略。
iota
iota,特殊常量,可以認(rèn)為是一個(gè)可以被編譯器修改的常量。
在每一個(gè)const關(guān)鍵字出現(xiàn)時(shí),被重置為0,然后再下一個(gè)const出現(xiàn)之前,每出現(xiàn)一次iota,其所代表的數(shù)字會(huì)自動(dòng)增加1。
...const ( A = 'a' //97 B = iota //1 C //2 D = "nick" //"nick" iota += 1 E //"nick" iota += 1 F = 618 //618 iota +=1 G //618 iota +=1 H = iota //7 I //8) ...
基本數(shù)據(jù)類型
布爾型
布爾型的值只可以是常量 true 或者 false。
var a boolvar a bool = truevar a = false
數(shù)字類型
int:
uint8(無(wú)符號(hào) 8 位整型 (0 到 255))
uint16(無(wú)符號(hào) 16 位整型 (0 到 65535))
uint32(無(wú)符號(hào) 32 位整型 (0 到 4294967295))
uint64(無(wú)符號(hào) 64 位整型 (0 到 18446744073709551615))
int8(有符號(hào) 8 位整型 (-128 到 127))
int16(有符號(hào) 16 位整型 (-32768 到 32767))
int32(有符號(hào) 32 位整型 (-2147483648 到 2147483647))
int64(有符號(hào) 64 位整型 (-9223372036854775808 到 9223372036854775807))
float:
float32(IEEE-754 32位浮點(diǎn)型數(shù))
float64(IEEE-754 64位浮點(diǎn)型數(shù))
complex64(32 位實(shí)數(shù)和虛數(shù))
complex128(64 位實(shí)數(shù)和虛數(shù))
其它:
byte(類似 uint8)
rune(類似 int32)
uint(32 或 64 位)
int(與 uint 一樣大?。?/p>
uintptr(無(wú)符號(hào)整型,用于存放一個(gè)指針)
類型轉(zhuǎn)換
package main func main() { var a int var b int32 var c int64 a = 15 //b = a + a // compiler error b = int32(a + a) // ok b = b + 5 // ok: 5 is a constant c = c + 5 // ok}
字符類型
存儲(chǔ)為ascii碼
var a byte = 'a'fmt.Println(a) //97
字符串類型
字符串表示兩種方式:
雙引號(hào)
`` (反引號(hào),不轉(zhuǎn)義)
string底層就是一個(gè)byte的數(shù)組
string本身是不可變的,因此要改變string中字符,需要如下操作:
str := "hello world" s := []byte(str) s[0] = 'o' str = string(s)
操作符
算術(shù)運(yùn)算符
+ 相加
- 相減
* 相乘
/ 相除
% 求余
++ 自增
-- 自減
關(guān)系運(yùn)算符
== 檢查兩個(gè)值是否相等,如果相等返回 True 否則返回 False。
!= 檢查兩個(gè)值是否不相等,如果不相等返回 True 否則返回 False。
> 檢查左邊值是否大于右邊值,如果是返回 True 否則返回 False。
< 檢查左邊值是否小于右邊值,如果是返回 True 否則返回 False。
>= 檢查左邊值是否大于等于右邊值,如果是返回 True 否則返回 False。
<= 檢查左邊值是否小于等于右邊值,如果是返回 True 否則返回 False。
邏輯運(yùn)算符
&& 邏輯 AND 運(yùn)算符。 如果兩邊的操作數(shù)都是 True,則條件 True,否則為 False。
|| 邏輯 OR 運(yùn)算符。 如果兩邊的操作數(shù)有一個(gè) True,則條件 True,否則為 False。
! 邏輯 NOT 運(yùn)算符。 如果條件為 True,則邏輯 NOT 條件 False,否則為 True。
位運(yùn)算符
位運(yùn)算符對(duì)整數(shù)在內(nèi)存中的二進(jìn)制位進(jìn)行操作。
& 按位與運(yùn)算符"&"是雙目運(yùn)算符。 其功能是參與運(yùn)算的兩數(shù)各對(duì)應(yīng)的二進(jìn)位相與。
| 按位或運(yùn)算符"|"是雙目運(yùn)算符。 其功能是參與運(yùn)算的兩數(shù)各對(duì)應(yīng)的二進(jìn)位相或。
^ 按位異或運(yùn)算符"^"是雙目運(yùn)算符。 其功能是參與運(yùn)算的兩數(shù)各對(duì)應(yīng)的二進(jìn)位相異或,當(dāng)兩對(duì)應(yīng)的二進(jìn)位相異時(shí),結(jié)果為1。
<< 左移運(yùn)算符"<<"是雙目運(yùn)算符。左移n位就是乘以2的n次方。 其功能把"<<"左邊的運(yùn)算數(shù)的各二進(jìn)位全部左移若干位,由"<<"右邊的數(shù)指定移動(dòng)的位數(shù),高位丟棄,低位補(bǔ)0。
>> 右移運(yùn)算符">>"是雙目運(yùn)算符。右移n位就是除以2的n次方。 其功能是把">>"左邊的運(yùn)算數(shù)的各二進(jìn)位全部右移若干位,">>"右邊的數(shù)指定移動(dòng)的位數(shù)。
賦值運(yùn)算符
= 簡(jiǎn)單的賦值運(yùn)算符,將一個(gè)表達(dá)式的值賦給一個(gè)左值
+= 相加后再賦值 (C += A 等于 C = C + A)
-= 相減后再賦值 (C -= A 等于 C = C - A)
*= 相乘后再賦值 (C *= A 等于 C = C * A)
/= 相除后再賦值 (C /= A 等于 C = C / A)
%= 求余后再賦值 (C %= A 等于 C = C % A)
<<= 左移后賦值 (C <<= 2 等于 C = C << 2)
>>= 右移后賦值 (C >>= 2 等于 C = C >> 2)
&= 按位與后賦值 (C &= 2 等于 C = C & 2)
^= 按位異或后賦值 (C ^= 2 等于 C = C ^ 2)
|= 按位或后賦值 (C |= 2 等于 C = C | 2)
流程控制
If/else & for & range
注意 else if / else 位置
if condition1 { } else if condition2 { } else if condition3 {? } else { }
for循環(huán)條件沒(méi)有小括號(hào)
for i := 0; i < 10; i++ { }
死循環(huán)
for true { }可以簡(jiǎn)寫(xiě)為:for { }
range
for i, v := range str { }
range栗子
switch case
Go里面switch默認(rèn)相當(dāng)于每個(gè)case最后帶有break,匹配成功后不會(huì)自動(dòng)向下執(zhí)行其他case,而是跳出整個(gè)switch。
switch var {case var1:case var2:case var3:default: }
switch 栗子一
switch 栗子二
switch 栗子三
fallthrough
可以使用fallthrough強(qiáng)制執(zhí)行后面的case代碼。
fallthrough栗子
label & goto
label要寫(xiě)在for循環(huán)的開(kāi)始而不是結(jié)束的地方。直接break退出到指定的位置。
func lab() { LABLE: for i := 0; i < 10; i++ { for true { i++ if i == 6 { break LABLE } fmt.Println(i) } } }
goto語(yǔ)句可以跳轉(zhuǎn)到本函數(shù)內(nèi)的某個(gè)標(biāo)簽
func got() { i := 0HERE: fmt.Println(i) i++ if i == 5 { return } goto HERE }
select
select與switch類似,不過(guò)select有較多限制。
每個(gè)case語(yǔ)句里必須是一個(gè)channel操作;
select {case ch <- 0: //如果0寫(xiě)入,則進(jìn)行該casecase <- ch: //如果讀到數(shù)據(jù),則進(jìn)行該casedefault: //如果上面的都沒(méi)有成功,則進(jìn)入default處理}
select栗子一
select栗子二(channel超時(shí)處理)
函數(shù)
Go 語(yǔ)言最少有個(gè) main() 函數(shù)。
函數(shù)聲明告訴了編譯器函數(shù)的名稱,返回類型,和參數(shù)。
不支持重載,一個(gè)包不能有兩個(gè)名字一樣的函數(shù)。
func function_name( [parameter list] ) [return_types] { 函數(shù)體 }
命名返回值的名字(return可以不指定變量):
栗子一
栗子二
_標(biāo)識(shí)符,用來(lái)忽略返回值:
栗子
函數(shù)也是一種類型,一個(gè)函數(shù)可以賦值給變量
package main import "fmt"//申明一個(gè)函數(shù)類型type add_func func(int, int) intfunc add(a, b int) int { return a + b } func operator(op add_func, a int, b int) int { return op(a, b) } func main() { c := add fmt.Println(c) //0x1087050 sum := operator(c, 1, 2) fmt.Println(sum) //300}
可變參數(shù)
其中arg是一個(gè)slice,我們可以通過(guò)arg[index]依次訪問(wèn)所有參數(shù);通過(guò)len(arg)來(lái)判斷傳遞參數(shù)的個(gè)數(shù)。
0個(gè)或多個(gè)參數(shù) func add(arg…int) int { }
1個(gè)或多個(gè)參數(shù) func add(a int, arg…int) int { }
2個(gè)或多個(gè)參數(shù) func add(a int, b int, arg…int) int { }
多參數(shù)栗子
main & init & defer
main & init
init() 方法是在任何package中都可以出現(xiàn);
main() 方法只能用在package main 中。
Go程序會(huì)自動(dòng)調(diào)用init()和main(),所以你不需要在任何地方調(diào)用這兩個(gè)函數(shù)。
每個(gè)package中的init函數(shù)都是可選的,但package main就必須包含一個(gè)main函數(shù)。
main()函數(shù)不能帶參數(shù),也不能定義返回值。命令行傳入的參數(shù)在os.Args變量中保存。如果需要支持命令行開(kāi)關(guān),可使用flag包。
defer
當(dāng)函數(shù)返回時(shí),執(zhí)行defer語(yǔ)句;
多個(gè)defer語(yǔ)句,按先進(jìn)后出的方式執(zhí)行;
defer語(yǔ)句中的變量,在defer聲明時(shí)確定變量。
defer 栗子
作用域
在函數(shù)內(nèi)部聲明的變量叫做局部變量,生命周期僅限于函數(shù)內(nèi)部。
在函數(shù)外部聲明的變量叫做全局變量,生命周期作用于整個(gè)包,如果是大寫(xiě)的,則作用于整個(gè)程序。
作用域栗子
匿名函數(shù) & 閉包
匿名函數(shù)
匿名函數(shù)是由一個(gè)不帶函數(shù)名的函數(shù)聲明和函數(shù)體組成。
package main func main() { f := func(x, y int) int { return x + y } f(1,1) ch := make(chan int) func (ch chan int) { ch <- 9 }(ch) }
閉包
閉包是一個(gè)函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。
函數(shù)可以存儲(chǔ)到變量中作為參數(shù)傳遞給其它函數(shù),能夠被函數(shù)動(dòng)態(tài)的創(chuàng)建和返回。
func Adder() func(int) int { var x int return func(d int) int { x += d return x } } f := Adder() fmt.Println(f(1)) //1fmt.Println(f(10)) //11fmt.Println(f(100)) //111
閉包栗子二
值傳遞 & 引用傳遞
無(wú)論是值傳遞,還是引用傳遞,傳遞給函數(shù)的都是變量的副本;
值傳遞是值的拷貝,引用傳遞是地址的拷貝;
一般來(lái)說(shuō),地址拷貝更為高效。而值拷貝取決于拷貝的對(duì)象大小,對(duì)象越大,則性能越低。
map、slice、chan、指針、interface默認(rèn)以引用的方式傳遞。
new 內(nèi)置函數(shù) 用來(lái)分配內(nèi)存,主要用來(lái)分配值類型,比如int、struct,返回的是指針;
make 內(nèi)置函數(shù) 用來(lái)分配內(nèi)存,主要用來(lái)分配引用類型,比如chan、map、slice。
程序初始化與執(zhí)行過(guò)程
程序的初始化和執(zhí)行都起始于main包。
如果main包還導(dǎo)入了其它的包,那么就會(huì)在編譯時(shí)將它們依次導(dǎo)入。
有時(shí)一個(gè)包會(huì)被多個(gè)包同時(shí)導(dǎo)入,那么它只會(huì)被導(dǎo)入一次(例如很多包可能都會(huì)用到fmt包,但它只會(huì)被導(dǎo)入一次,因?yàn)闆](méi)有必要導(dǎo)入多次)。
當(dāng)一個(gè)包被導(dǎo)入時(shí),如果該包還導(dǎo)入了其它的包,那么會(huì)先將其它包導(dǎo)入進(jìn)來(lái),然后再對(duì)這些包中的包級(jí)常量和變量進(jìn)行初始化,接著執(zhí)行init函數(shù)(如果有的話),依次類推。
等所有被導(dǎo)入的包都加載完畢了,就會(huì)開(kāi)始對(duì)main包中的包級(jí)常量和變量進(jìn)行初始化,然后執(zhí)行main包中的init函數(shù)(如果存在的話),最后執(zhí)行main函數(shù)。
指針類型(&*)
普通類型,變量存的就是值,也叫值類型;
指針類型,變量存的是一個(gè)地址,這個(gè)地址存的才是值。
變量是一種占位符,用于引用計(jì)算機(jī)內(nèi)存地址;
Go 語(yǔ)言的取地址符是 &,放到一個(gè)變量前使用就會(huì)返回相應(yīng)變量的內(nèi)存地址。
獲取指針類型所指向的值,使用:*。
一個(gè)指針變量可以指向任何一個(gè)值的內(nèi)存地址它指向那個(gè)值的內(nèi)存地址。
申明如下:
age * height *float32
當(dāng)一個(gè)指針被定義后沒(méi)有分配到任何變量時(shí),它的值為 nil。
nil 指針也稱為空指針。
栗子
package main import "fmt"func main() { var ptr *int num := 100 ptr = &num fmt.Println(ptr) //0xc42000e1f8 fmt.Println(*ptr) //100 *ptr = 200 fmt.Println(num) //200}
package main import "fmt"func change(num *int) { fmt.Println(num) //0xc42000e1f8 fmt.Println(*num) //100 *num = 1000 fmt.Println(num) //0xc42000e1f8 fmt.Println(*num) //1000} func main() { num := 100 fmt.Println(&num) //0xc42000e1f8 change(&num) fmt.Println(&num) //0xc42000e1f8 fmt.Println(num) //1000}
http://www.cnblogs.com/suoning/p/7048996.html