腳本化的語法,容易上手。html
靜態類型+編譯性,開發、運行效率都有保證java
函數式 & 面向對象 兩種編程範式,mysql
原生支持併發編程支持,下降開發成本,維護成本,以及更好的兼容性,效率。linux
劣勢:語法糖沒有 Python 和 Ruby 多。運行效率不及C,但已趕超C++,Java。第三方庫很少,就是輪子少(喜歡造輪子的能夠加入golang輪子大軍)。nginx
官方: https://golang.org/git
國內官方站點: https://go-zh.org/github
http://golang.org/dl/ 下載最新Go語言二進制包golang
wget https://dl.google.com/go/go1.13.15.linux-amd64.tar.gz tar -C /usr/local -xzf go1.13.15.linux-amd64.tar.gz export PATH=$PATH:/usr/local/go/bin go version
GOROOT, GOPATH, GOBIN, PATH, 如今安裝的最新golang runtiem都不用配置了環境變量了。sql
break //退出循環 default //選擇結構默認項(switch、select) func //定義函數 interface //定義接口 select //channel case //選擇結構標籤 chan //定義channel const //常量 continue //跳過本次循環 defer //延遲執行內容(收尾工做) go //併發執行 map //map類型 struct //定義結構體 else //選擇結構 goto //跳轉語句 package //包 switch //選擇結構 fallthrough //?? if //選擇結構 range //從slice、map等結構中取元素 type //定義類型 for //循環 import //導入包 return //返回 var //定義變量
append | bool | byte | cap | close | complex | complex64 | complex128 | uint16 |
---|---|---|---|---|---|---|---|---|
copy | false | float32 | float64 | imag | int | int8 | int16 | uint32 |
int32 | int64 | iota | len | make | new | nil | panic | uint64 |
println | real | recover | string | true | uint | uint8 | uintptr |
不要求縮進,不要求末尾加分號——;,同一行代碼中有多個表達式,須要用 分號 分割。沒有使用的變量,包,會致使報錯。shell
每一個go源文件開頭必須是package開頭,定義本身的包
一個目錄下,只能有一個包名
一個可執行的文件必需要有 main()
函數
兩種引入風格
import "package1" import "package2"
import ( "package1" pa2 "package2" // 包別名,別名爲 pa2 . "fmt" _ "mysql" )
. "fmt"
方式引入包的化,使用fmt裏面的函數就可直接使用,不用帶 fmt 前綴了
若是引入的包不使用,會報錯, 或者加個前綴 _ 便可,這樣的下劃線會把引入的包的init函數執行一下。定義的變量不用,也會報錯。
定義 包內 初始化函數
func init() { }
只導入這個包部分,並運行init函數,因爲導入不全,因此在代碼中就不能使用這個包了。
import _ "MyPackage"
序號 | 類型和描述 |
---|---|
1 | 布爾型 布爾型的值只能夠是常量 true 或者 false。一個簡單的例子:var b bool = true。 |
2 | 數字類型 整型 int 和浮點型 float3二、float64,Go 語言支持整型和浮點型數字,而且支持複數,其中位的運算採用補碼。 |
3 | 字符串類型: 字符串就是一串固定長度的字符鏈接起來的字符序列。Go 的字符串是由單個字節鏈接起來的。Go 語言的字符串的字節使用 UTF-8 編碼標識 Unicode 文本。 |
4 | 派生類型: 包括: (a) 指針類型(Pointer) (b) 數組類型 (c) 結構化類型(struct) (d) Channel 類型 (e) 函數類型 (f) 切片類型 (g) 接口類型(interface) (h) Map 類型 |
使用 int 時,根據當前操做系統來的,64位系統對應 int64, 32位操做系統,對應int32.
分組聲明 var ( i int foo float32 name string ) 分組批量聲明、賦值 var a,b,c,d int = 1,2,3,4 a,b := 1,2
特殊變量 _
var
聲明,局部變量可省略做用域能夠分爲如下四個類型:
語句塊是由花括弧({})所包含的一系列語句。
在 Go 中還有不少的隱式語句塊:
斷言,顧名思義就是果斷的去猜想一個未知的事物。在 go 語言中,interface{} 就是這個神祕的未知類型,其斷言操做就是用來判斷 interface{} 的類型。
var foo interface{} = 22 f, ok := foo.(int) if !ok { t.Log("Guess wrong ...") } t.Logf("The type is : %T", f)
變量類型支持: bool, int, float, string
運算符 | 描述 | 實例 |
---|---|---|
+ | 相加 | A + B 輸出結果 30 |
- | 相減 | A - B 輸出結果 -10 |
* | 相乘 | A * B 輸出結果 200 |
/ | 相除 | B / A 輸出結果 2 |
% | 求餘 | B % A 輸出結果 0 |
++ | 自增 | A++ 輸出結果 11 |
-- | 自減 | A-- 輸出結果 9 |
運算符 | 描述 | 實例 |
---|---|---|
== | 檢查兩個值是否相等,若是相等返回 True 不然返回 False。 | (A == B) 爲 False |
!= | 檢查兩個值是否不相等,若是不相等返回 True 不然返回 False。 | (A != B) 爲 True |
> | 檢查左邊值是否大於右邊值,若是是返回 True 不然返回 False。 | (A > B) 爲 False |
< | 檢查左邊值是否小於右邊值,若是是返回 True 不然返回 False。 | (A < B) 爲 True |
>= | 檢查左邊值是否大於等於右邊值,若是是返回 True 不然返回 False。 | (A >= B) 爲 False |
<= | 檢查左邊值是否小於等於右邊值,若是是返回 True 不然返回 False。 | (A <= B) 爲 True |
運算符 | 描述 | 實例 | ||||
---|---|---|---|---|---|---|
&& | 邏輯 AND 運算符。 若是兩邊的操做數都是 True,則條件 True,不然爲 False。 | (A && B) 爲 False | ||||
\ | \ | 邏輯 OR 運算符。 若是兩邊的操做數有一個 True,則條件 True,不然爲 False。 | (A \ | \ | B) 爲 True | |
! | 邏輯 NOT 運算符。 若是條件爲 True,則邏輯 NOT 條件 False,不然爲 True。 | !(A && B) 爲 True |
運算符 | 描述 | 實例 | |||
---|---|---|---|---|---|
& | 按位與運算符"&"是雙目運算符。 其功能是參與運算的兩數各對應的二進位相與。 | (A & B) 結果爲 12, 二進制爲 0000 1100 | |||
\ | 按位或運算符"\ | "是雙目運算符。 其功能是參與運算的兩數各對應的二進位相或 | (A \ | B) 結果爲 61, 二進制爲 0011 1101 | |
^ | 按位異或運算符"^"是雙目運算符。 其功能是參與運算的兩數各對應的二進位相異或,當兩對應的二進位相異時,結果爲1。 | (A ^ B) 結果爲 49, 二進制爲 0011 0001 | |||
<< | 左移運算符"<<"是雙目運算符。左移n位就是乘以2的n次方。 其功能把"<<"左邊的運算數的各二進位所有左移若干位,由"<<"右邊的數指定移動的位數,高位丟棄,低位補0。 | A << 2 結果爲 240 ,二進制爲 1111 0000 | |||
>> | 右移運算符">>"是雙目運算符。右移n位就是除以2的n次方。 其功能是把">>"左邊的運算數的各二進位所有右移若干位,">>"右邊的數指定移動的位數。 | A >> 2 結果爲 15 ,二進制爲 0000 1111 |
運算符 | 描述 | 實例 | |||
---|---|---|---|---|---|
= | 簡單的賦值運算符,將一個表達式的值賦給一個左值 | C = A + B 將 A + B 表達式結果賦值給 C | |||
+= | 相加後再賦值 | 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 |
優先級 | 運算符 | 功能 | ||
---|---|---|---|---|
9 | () [] -> . | 後綴運算 | ||
8 | ! *(指針) & ++ -- +(正號) -(負號) | 單目運算 | ||
7 | * / % + - | 算術運算,加減乘除 | ||
6 | << >> | 位運算 | ||
5 | == != < <= > >= | 邏輯運算、不等、等 | ||
4 | & \ | ^ | 按位 邏輯與、或 | |
3 | \ | \ | && | 邏輯或、與 |
2 | = += -= *= 等等 | 賦值運算 | ||
1 | , | 逗號 |
一元
、賦值
這兩大運算符是 從右到左
關聯,其餘都是 從左到右
關聯。
注意:優先級 值越大則優先級越高。爲了方便理解、記憶,我對沒有嚴格按照優先級製表,只是作了個大概!!
更詳細的
var number int = 37 if number += 4; 10 > number { fmt.Print("less than 10:", number) } else if 10 < number { number -= 2 fmt.Print("greater 10:", number) } else { }
package main import ( "fmt" "math/rand" ) func main() { ia := []interface{}{byte(6), 'a', uint(10), int32(-4), "CC"} v := ia[rand.Intn(4)] // 值 switch switch v { case 'a' : fmt.Println("char: ", v) case 10 : fmt.Println("uint: ", v) case -4 : fmt.Println("int: ", v) case 0.1 : fallthrough caes "0.1" fmt.Println("float: ", v) default : fmt.Println("byte: ", v) } // 變量類型 switch switch interface{}(v).(type) { case string : fmt.Printf("Case A.") case byte : fmt.Printf("Case B.") case int : fmt.Printf("Case B.") default: fmt.Println("Unknown!") } }
注意,go語言和其餘語言不一樣的時,每一個case代碼末尾會自動加上break
操做, 若是你須要使用 fallthrough
來抵消默認的 break
select 用於管道
是的 golang
的 for
集 for
,foreach
,for in
,while
於一體。
do while
表示:golang你這麼繞,不優雅
package main import ( "fmt" "time" ) func main() { map1 := map[int]string{1: "Golang", 2: "Java", 3: "Python", 4: "C"} n := 1 for { // 省略則默認是true if n > 3 { break; } fmt.Println("for true map item: ", map1[n]) time.Sleep(1) n++ } for i := 1; i < 4; i++ { fmt.Println("for i map item: ", map1[i]) } for k,v := range map1 { fmt.Print(k, ":", v) } }
goto 是跳過代碼塊
package main import ( "fmt" "time" ) func main() { code: fmt.Println("do some thing~") time.Sleep(1) goto code }
break 跳出並結束循環
continue 跳過當前循環
雖然不能和PHP
那樣break 2
跳出多層, 單隻要有goto就能幹不少事了。golang給 循環 就分配了一個 for,語句跳轉語句卻整了那麼多花樣
內建方法就是不須要引入包就能用的
make 能夠建立 slice、map、chan,返回指針類型
一股c編程風格撲面而來, char ptr = (char )malloc(sizeof(char) * 5);
內存置0,返回傳入類型的指針地址
package main import fmt import reflect func main() { mSlice := make([]string, 3) mSlice[0] = "dog" mSlice[1] = "cat" mSlice[2] = "pig" fmt.Println("animals: ", mSlice) mMap := make(map[int]string) mMap[10] = "dog" mMap['2'] = "cat" fmt.Println(reflect.TypeOf(mMap)) fmt.Println("animals :: ", mMap) nMap := new(map[int]string) fmt.Println(reflect.TypeOf(nMap)) }
slice可使用copy,append 函數
delete 是專門用來刪除 map
package main import "fmt" func main() { mSlice := make([]string, 3) mSlice[0] = "dog" mSlice[1] = "cat" mSlice[2] = "pig" fmt.Println("animals: ", mSlice) // append(mSlice, "id-3") // 這樣寫會致使報錯: append(mSlice, "id-3") evaluated but not used mSlice = append(mSlice, "id-3") fmt.Println("animals update:", mSlice) fmt.Println("animals len :", len(mSlice)) fmt.Println("animals cap:", cap(mSlice)) // newSlice := make([]string) // 這樣寫致使報錯:missing len argument to make([]string) // newSlice := make([]string, 2) // 這樣寫會致使數據丟失2個,不會自動擴容 newSlice := make([]string, 3) // 不要屢次定義初始化:no new variables on left side of := copy(mSlice, newSlice) // 這樣反向copy,會致使前面的幾個數組元素被置爲空 // copy(newSlice, mSlice) fmt.Println("animals dst:", mSlice) fmt.Println("animals copy:", newSlice) delete(mMap, 50) fmt.Println(mMap) }
異常處理
panic() 拋出異常
recover() 獲取異常
報錯會致使程序代碼中斷,不會再執行後續操做
package main import "fmt" import "errors" func panicFunc() { defer func() { // recover() message := recover() // 聲明瞭message 變量就須要使用哦,否則報錯 fmt.Println("panice msg: ", message) switch message.(type) { case string: case error: fmt.Println("panice error msg: ", message) default: } }() // panic("報錯啦") panic(errors.New("I am error.")) } func main() { panicFunc() }
len能夠計算 string, array, slice, map, chan
cap 能夠計算 slice, map, chan
len()
獲取數組長度cap()
獲取佔用空間分配close()
用於關閉管道——chan當聲明一個數組時,go會預先分配一部分空間給當前數組,獲取實際空間佔用大小,使用cap()
不用像PHP那樣,strlen(), count(), length 傻傻分不清楚了。
package main import "fmt" func main() { mSlice := make([]string, 3) mSlice[0] = "dog" mSlice[1] = "cat" mSlice[2] = "pig" fmt.Println("animals: ", mSlice) fmt.Println("animals update:", mSlice) fmt.Println("animals len :", len(mSlice)) fmt.Println("animals cap:", cap(mSlice)) mChan := make(chan int, 1) close(mChan) mChan <- 1 // 會致使報錯: panic: send on closed channel }
定一個當前方法關閉時,運行的代碼, 壓棧設計,先聲明的後執行。
package main import "fmt" type Dog struct { ID int Name string Age int32 } func main() { var dog Dog dog.ID = 1 dog.Name = "haha" dog.Age = 3 fmt.Println("print Dog Struct", dog) dog2 := Dog{ID:2, Name:"san", Age:4} fmt.Println("print Dog 2 Struct", dog2) dog3 := new(Dog) dog3.ID = 3 dog3.Name = "Tom" dog3.Age = 5 fmt.Println("print Dog 3 Struct", dog) }
輸出
print Dog Struct {1 haha 3} print Dog 2 Struct {2 san 4} print Dog 3 Struct &{3 Tom 5}
/* define an interface */ type interface_name interface { method_name1 [return_type] method_name2 [return_type] ... method_namen [return_type] } /* define a struct */ type struct_name struct { /* variables */ } /* implement interface methods*/ func (struct_name_variable struct_name) method_name1() [return_type] { /* method implementation */ } ... func (struct_name_variable struct_name) method_namen() [return_type] { /* method implementation */ }
須要引入包 encoding/json
, 兩個函數分別是 json.Marshal()
, json.Unmarshal()
.
注意,最後一個是英文字母小寫的L
,不是1
package main import "fmt" import "encoding/json" type ServerInfo struct { SerName string SerIp string SerPort uint16 } func main() { server := new(ServerInfo) server.SerName = "http-nginx" server.SerIp = "127.0.0.1" server.SerPort = 8080 re,err := json.Marshal(server) if nil != err { fmt.Println("error: ", err.Error()) } else { fmt.Println("struct json bytes: ", re) fmt.Println("struct json string: ", string(re)) } mServer := make(map[string]interface{}) mServer["serverName"] = "apache2-http" mServer["serIp"] = "192.168.30.133" mServer["serPort"] = "3033" mRe,err := json.Marshal(mServer) if nil != err { fmt.Println("error: ", err.Error()) } else { fmt.Println("map json string: ", string(mRe)) } }
輸出
struct json bytes: [123 34 83 101 114 78 97 109 101 34 58 34 104 116 116 112 45 110 103 105 110 120 34 44 34 83 101 114 73 112 34 58 34 49 48 46 49 48 48 46 49 55 46 50 55 58 51 48 48 48 49 34 44 34 83 101 114 80 111 114 116 34 58 56 48 56 48 125] struct json string: {"SerName":"http-nginx","SerIp":"10.100.17.27:30001","SerPort":8080} map json string: {"serIp":"192.168.30.133","serPort":"3033","serverName":"apache2-http"}
ps: 我也不知道
10.100.17.27:30001
是怎麼回事
可使用 tag 來作 mapping,
package main import "fmt" import "encoding/json" type ServerInfo struct { SerName string `json:"name"` SerIp string `json:"ip"` SerPort uint16 `json:"port"` } func main() { // jsonStr := "{\"SerName\":\"http-nginx\",\"SerIp\":\"10.100.17.27:30001\",\"SerPort\":8080}" \\ 雙引號注意轉義 jsonStr := "{\"name\":\"http-nginx\",\"ip\":\"10.100.17.27:30001\",\"port\":8080}" sServer := new(ServerInfo) jsonBytes := []byte(jsonStr) uerr := json.Unmarshal(jsonBytes, &sServer) if nil != uerr { fmt.Println("error: ", err.Error()) } else { fmt.Println("uns struct: ", sServer) } jsonStr3 := `{"serIp":"192.168.30.133","serPort":"3033","serverName":"apache2-http"}` \\ 使用鍵盤1旁邊的 ` 符號包裹雙引號就不用轉義了 uSer := make(map[string]interface{}) uErr := json.Unmarshal([]byte(jsonStr3), &uSer) if nil != uErr { fmt.Println("error: ", uErr.Error()) } else { fmt.Println("unmar map: ", uSer) } }
輸出
uns struct: &{http-nginx 10.100.17.27:30001 8080} unmar map: map[serIp:192.168.30.133 serPort:3033 serverName:apache2-http]
tag
這個東東把,就是json的別名,感受這個功能是go的特點,與encoding/json
包緊密結合。
爲何會有這個東西,我估計是這個和 go命名規則 有關,go命名規則,要求public的變量開頭要大寫,小寫開頭的變量是private的,因此,json中的變量就會影響一個接口體變量的訪問權限,爲了避免像java那樣複雜,提供了方便的tag功能。
package main import "fmt" import "encoding/json" type ServerInfo struct { SerName string `json:"name"` SerIp string `json:"ip"` SerPort uint16 `json:"port"` } func main() { server := new(ServerInfo) server.SerName = "http-nginx" server.SerIp = "127.0.0.1" server.SerPort = 8080 re,err := json.Marshal(server) if nil != err { fmt.Println("error: ", err.Error()) } else { fmt.Println("struct json string: ", string(re)) } }
輸出
struct json string: {"name":"http-nginx","ip":"10.100.17.27:30001","port":8080} map json strin
這就比如是Linux 裏的 /dev/null
, 因爲go語言要求聲明的變量必須被使用,返回的變量必須被接收,那麼真有個變量沒用但必需要接受怎麼辦呢,就把返回的參數給他。例如:
package main import "fmt" var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} func main() { for _, v := range pow { fmt.Printf("value is %d\n", v) } }
這裏咱們只要值,不要key的信息,返回的key不能不收不是,但我也不像把它輸出出來,就讓 _
來接收好了。
引入包, 並不直接使用這個包,運行時執行一次它的 init()
函數,
import ( _ "github.com/go-sql-driver/mysql" "github.com/jinzhu/gorm" )