加 Golang學習 QQ羣共同窗習進步成家立業工做 ^-^ 羣號:96933959數組
變量名由字母、數字、下劃線組成,不能以數字開頭。閉包
... var ( A int //默認爲0 B string //默認爲"" C bool //默認爲false Name string = "suoning" Age = 18 // 自動識別類型 ) func main() { sex := "man" //等價於 var sex string = "man" var girlfriend string //聲明變量 girlfriend = "Dawn" //變量賦值 Name := "Nick" //正確 //girlfriend := "Jenny" //錯誤的!不能申明兩次 ... }
常量使用const 修飾,表明永遠是隻讀的,不能修改。ide
常量中的數據類型只能夠是布爾型、數字型(整數型、浮點型和複數)和字符串型。函數
語法:const identifier [type] = value,其中type能夠省略。性能
iota,特殊常量,能夠認爲是一個能夠被編譯器修改的常量。學習
在每個const關鍵字出現時,被重置爲0,而後再下一個const出現以前,每出現一次iota,其所表明的數字會自動增長1。ui
... 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 ) ...
布爾型的值只能夠是常量 true 或者 false。spa
var a bool var a bool = true var a = false
int:命令行
float:3d
其它:
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 }
存儲爲ascii碼
var a byte = 'a' fmt.Println(a) //97
字符串表示兩種方式:
string底層就是一個byte的數組
string自己是不可變的,所以要改變string中字符,須要以下操做:
str := "hello world" s := []byte(str) s[0] = 'o' str = string(s)
位運算符對整數在內存中的二進制位進行操做。
注意 else if / else 位置
if condition1 { } else if condition2 { } else if condition3 { } else { }
for循環條件沒有小括號
for i := 0; i < 10; i++ { }
死循環
for true { } 能夠簡寫爲: for { }
range
for i, v := range str { }
package main import ( "fmt" ) func ran(str string) { for i, v := range str { fmt.Printf("index[%d] val[%c] len[%d]\n", i, v, len([]byte(string(v)))) } } func main() { ran("Love, 索寧") } 輸出結果: index[0] val[L] len[1] index[1] val[o] len[1] index[2] val[v] len[1] index[3] val[e] len[1] index[4] val[,] len[1] index[5] val[ ] len[1] index[6] val[索] len[3] index[9] val[寧] len[3]
Go裏面switch默認至關於每一個case最後帶有break,匹配成功後不會自動向下執行其餘case,而是跳出整個switch。
switch var { case var1: case var2: case var3: default: }
func sw(num int) { switch num { case 1, 2, 3: fmt.Printf("%s in 1,2,3\n", num) case 4, 5, 6: fmt.Printf("%s in 4,5,6\n", num) fallthrough case 7, 8, 9: fmt.Printf("%s big 789\n", num) default: fmt.Printf("default...\n") } }
func sw2(num int) { switch { case num > 0 && num < 4: fmt.Printf("%s in 1,2,3\n", num) case num > 4 && num < 7: fmt.Printf("%s in 4,5,6\n", num) fallthrough case num > 7 && num < 10: fmt.Printf("%s big 789\n", num) default: fmt.Printf("default...\n") } }
func sw3() { switch num := 5; { case num > 0 && num < 4: fmt.Printf("%s in 1,2,3\n", num) case num > 4 && num < 7: fmt.Printf("%s in 4,5,6\n", num) fallthrough case num > 7 && num < 10: fmt.Printf("%s big 789\n", num) default: fmt.Printf("default...\n") } }
可使用fallthrough強制執行後面的case代碼。
package main import "fmt" func main() { switch { case false: fmt.Println("The integer was <= 4") fallthrough case true: fmt.Println("The integer was <= 5") fallthrough case false: fmt.Println("The integer was <= 6") fallthrough case true: fmt.Println("The integer was <= 7") case false: fmt.Println("The integer was <= 8") fallthrough default: fmt.Println("default case") } } 運行結果: The integer was <= 5 The integer was <= 6 The integer was <= 7
label要寫在for循環的開始而不是結束的地方。直接break退出到指定的位置。
func lab() { LABLE: for i := 0; i < 10; i++ { for true { i++ if i == 6 { break LABLE } fmt.Println(i) } } }
goto語句能夠跳轉到本函數內的某個標籤
func got() { i := 0 HERE: fmt.Println(i) i++ if i == 5 { return } goto HERE }
select與switch相似,不過select有較多限制。
每一個case語句裏必須是一個channel操做;
select { case ch <- 0: //若是0寫入,則進行該case case <- ch: //若是讀到數據,則進行該case default: //若是上面的都沒有成功,則進入default處理 }
package main import ( "fmt" "time" ) /* 隨機向ch中寫入一個0或者1的過程,固然這是個死循環。 */ func main() { ch := make(chan int, 1) for { select { case ch <- 0: case ch <- 1: } i := <-ch fmt.Println(i) time.Sleep(time.Second) } }
package main import ( "fmt" "time" ) /* channel超時處理 一直沒有從ch中讀取到數據,但從timeout中讀取到了數據 */ func main() { ch := make(chan bool) timeout := make(chan bool, 1) go func() { time.Sleep(time.Second*2) timeout <- true }() select { case <- ch: fmt.Println("This is ch.") case <- timeout: fmt.Println("This is timeout.") } }
Go 語言最少有個 main() 函數。
函數聲明告訴了編譯器函數的名稱,返回類型,和參數。
不支持重載,一個包不能有兩個名字同樣的函數。
func function_name( [parameter list] ) [return_types] {
函數體
}
命名返回值的名字(return能夠不指定變量):
func add(a, b int) (c int) { c = a + b return }
func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a +b)/2 return }
_標識符,用來忽略返回值:
func calc(a, b int) (sum int, avg int) { sum = a + b avg = (a +b)/2 return } func main() { sum, _ := calc(100, 200) }
函數也是一種類型,一個函數能夠賦值給變量
package main import "fmt" //申明一個函數類型 type add_func func(int, int) int func 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 }
其中arg是一個slice,咱們能夠經過arg[index]依次訪問全部參數;經過len(arg)來判斷傳遞參數的個數。
0個或多個參數 func add(arg…int) int { }
1個或多個參數 func add(a int, arg…int) int { }
2個或多個參數 func add(a int, b int, arg…int) int { }
package main import ( "fmt" ) //返回值指定爲sum變量,默認會return這個變量 func add(a int, b int, arg ...int) (sum int) { sum = a + b for i := 0; i < len(arg); i++ { sum += arg[i] } return } func concat(s string, arg ...string) string { str := s for i := 0; i < len(arg); i++ { str += arg[i] } return str } func main() { sum := add(1, 2, 3, 4, 5, 6, 7) fmt.Println(sum) //28 str := concat("nick", " ", "and", " ", "dawn", ".") fmt.Println(str) //nick and dawn. }
package main import "fmt" //聲明defer時,變量i就爲0 func test1() { i := 0 defer fmt.Println(i) i++ return } //棧,先進先出 func test2() { for i := 0; i < 5; i++ { defer fmt.Printf("->%d", i) } } func main() { test1() test2() } 輸出: 0 ->4->3->2->1->0
package main import ( "fmt" ) func main() { defer_call() } func defer_call() { defer func() { fmt.Println("打印前") }() defer func() { fmt.Println("打印中") }() defer func() { fmt.Println("打印後") }() panic("觸發異常") } /* 打印後 打印中 打印前 panic: 觸發異常 */
package main import "fmt" var name string func main() { name = "Nick" fmt.Println(name) f1() } func f1() { name := "Dawn" fmt.Println(name) f2() } func f2() { fmt.Println(name) } 輸出: Nick Dawn Nick
匿名函數是由一個不帶函數名的函數聲明和函數體組成。
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) }
閉包是一個函數和與其相關的引用環境組合而成的實體。
函數能夠存儲到變量中做爲參數傳遞給其它函數,可以被函數動態的建立和返回。
func Adder() func(int) int { var x int return func(d int) int { x += d return x } } f := Adder() fmt.Println(f(1)) //1 fmt.Println(f(10)) //11 fmt.Println(f(100)) //111
package main import ( "fmt" "strings" ) func makeSuffix(suffix string) func(string) string { return func(name string) string { if !strings.HasSuffix(name, suffix) { return name + suffix } return name } } func main() { f1 := makeSuffix(".png") fmt.Println(f1("name1")) //name1.png fmt.Println(f1("name2")) //name2.png f2 := makeSuffix(".jpg") fmt.Println(f2("name1")) //name1.jpg fmt.Println(f2("name2")) //name2.jpg }
不管是值傳遞,仍是引用傳遞,傳遞給函數的都是變量的副本;
值傳遞是值的拷貝,引用傳遞是地址的拷貝;
通常來講,地址拷貝更爲高效。而值拷貝取決於拷貝的對象大小,對象越大,則性能越低。
map、slice、chan、指針、interface默認以引用的方式傳遞。
new 內置函數 用來分配內存,主要用來分配值類型,好比int、struct,返回的是指針;
make 內置函數 用來分配內存,主要用來分配引用類型,好比chan、map、slice。
普通類型,變量存的就是值,也叫值類型;
指針類型,變量存的是一個地址,這個地址存的纔是值。
變量是一種佔位符,用於引用計算機內存地址;
Go 語言的取地址符是 &,放到一個變量前使用就會返回相應變量的內存地址。
獲取指針類型所指向的值,使用:*。
一個指針變量能夠指向任何一個值的內存地址它指向那個值的內存地址。
申明以下:
var age *int //指向整型 var height *float32 //指向浮點型
當一個指針被定義後沒有分配到任何變量時,它的值爲 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 }