最簡單的一個go程序:golang
package main import "fmt" func main() { fmt.Println("Hello, World!") }
Go源程序由幾部分構成:數組
package
用於包聲明:package main
表示一個可獨立執行的程序,** Go應用程序必須包含名爲main
的包**,若是無main
包,那麼編譯器會提示"cannot run non-main package";import
用於導入須要引用的外部包, import "fmt"
告訴 Go 編譯器這個程序須要使用 fmt 包;func main()
是程序的主函數,通常來講都是在啓動後第一個執行的函數(若是有init()
函數則會先執行init
函數);public
;protected
;變量分爲值類型和引用類型:閉包
Go語言中的變量類型基本涵蓋了C語言的基本類型,同時增長指定長度的類型,例如:int八、uint八、int1六、uint1六、int3二、uint32等。ide
Go語言中有多種定義變量的方法,分別介紹:函數
var v_name v_type
,範例:var varInPackage1 int // 本地變量,沒有賦初始值 var varInPackage2 int = 10 // 本地變量賦初始值爲10 var VarInPackage int = 20 // 全局變量賦初始值爲20
var intVar = 10 var stringVar = "String"
:=
進行賦值,這種定義只能位於函數體內,用於建立局部變量,因此必須確保變量沒有被定義過:intVar := 10 intVar1, strVar = 20, "StrValue" // 同時定義兩個變量 a, _ = 10, 20 // 忽略第二個參數
var ( a int b bool )
go語言中變量的做用域與C語言相同。post
數組的定義:測試
var variable_name [SIZE] variable_type
建立數組格式:ui
var balance1 [10] int32 // 建立一個容量爲10的數組 var balance2 = [5]float32{1.0, 2.0, 3.4, 7.0, 5.1} // 建立一個容量爲5的數組,而且賦初始值 var balance3 = [...]float32{1.0, 2.1, 3.4, 7.5, 5.0} // 建立一個數組容量由後面定義的數據決定
切片(slice)是對數組一個連續片斷的引用(該數組咱們稱之爲相關數組,一般是匿名的),因此切片是一個引用類型,切記不可用指針指向切片!!指針
和數組不一樣的是,切片的長度能夠在運行時修改,最小爲 0 最大爲相關數組的長度:切片是一個 長度可變的數組。code
切片的聲明格式:
var identifier []type // 注意方括號爲空
切片有幾種建立方法:
var slice1 []type = arr1[start:end] // arr1爲已經建立的數組或者切片
var x = []int{2, 3, 5, 7, 11} // 建立一個長度爲5的切片
slice1 := make([]type, len) // len爲切片的初始長度 slice1 := make([]type, len, cap) // cap爲切片初始容量
切片能夠調整容量,下面的代碼用於將sl
的容量增長1:
sl = sl[0:len(sl)+1]
下面的將去掉切片的第一個元素:
sl = sl[1:len(sl)]
Go語言中字符串是常量,不可變。
若是須要修改字符串中的某個數字,則須要將字符串轉化成切片後再進行修改。
例如,將字符串 "hello" 轉換爲 "cello":
s := "hello" c := []byte(s) c[0] = 'c' s2 := string(c) // s2 == "cello"
經過const
關鍵字建立常量,常量的定義方法與變量相似,差別在於將var
替換爲const
,範例:
const a string = "abc" const b = "abc"
下面介紹一個特殊的常量iota
,能夠認爲這個是在編譯前進由編譯器修改的常量。
在一個const
組中,首次使用iota
時值爲0,每使用一次,iota
自動加一,這種用法通常做爲enum
類型使用:
const ( a = iota // 首次調用,因此a=0 b // 不賦任何值時,就是使用與上一個變量相同的方式賦值,因此這個等價於 b = iota,即便不寫iota,編譯器默認就是自動調用 c // 等價於 c = iota ) const ( a1 = iota // 這是一個新的const組,iota初始值爲0,因此a1=0 a2 // 等價於 a2 = iota )
Go語言提供了strings
包,專門處理string
類型的數據。
例如:
strings.Contains()
判斷字符串中是否包含特定字符串;strings.Index()
返回特定字符串在指定字符串中的位置;文檔能夠參考:https://studygolang.com/pkgdoc
Map 是一種無序的鍵值對的集合,Map 最重要的一點是經過 key 來快速檢索數據,key 相似於索引,指向數據的值。
Map 是一種集合,因此咱們能夠像迭代數組和切片那樣迭代它,可是Map 是無序的,咱們沒法決定它的返回順序,這是由於 Map 是使用 hash 表來實現的。
map聲明方式:
var map_variable map[key_data_type]value_data_type
map 是 引用類型 的: 內存用 make 方法來分配,最簡單的初始化:
var map1 = make(map[keytype]valuetype) var map1 = make(map[keytype]valuetype, cap) // 指定容量
也能夠帶初始值方式建立,例如:
mapCreated := map[string]float32{"C0": 16.35, "D0": 18.35}
範例:
var kvs = make(map[string]string) // 建立一個Map kvs["AAA"] = "aaa"; kvs["BBB"] = "bbb"; for k,v := range kvs { // 遍歷Map fmt.Printf("\tK=%s, V=%s\n", k, v) } v,ret := kvs["CCC"] // 查找map,第一個返回值是key對應的value,第二個返回值是結果 fmt.Printf("\tfind CCC, ret=%d, v=%s\n", ret, v)
if語句格式與C語言相比,只不過測試表達式不帶括號(也能夠帶括號),其餘與C語言相同:
if 測試表達式 { /* 在布爾表達式爲 true 時執行 */ } else { /* 在布爾表達式爲 false 時執行 */ }
Go的switch
與C的相似,與C的差別在於默認每一個case後面自帶break語句,若是不須要break
,則須要經過fallthrough
關鍵字指明。
範例:
switch marks { case 90: grade = "A" case 80: grade = "B" case 50,60,70 : grade = "C" fallthrough // 表示沒有break,至關於接着執行default裏面的語句 default: grade = "D" }
if
和switch
還有另一種寫法,支持接受一個初始化參數,格式以下:
if initstatement; condition {} switch initstatement; condition {}
例如:
if err := file.Chmod(0664); err != nil
循環控制:
for init; condition; post { } // 與C語言相同 for condition { } // 等同於 while(condition) for { } // 等同於 for(;;)
for
循環的init/post
段不支持經過,
分隔多個表達式,若是您須要初始化多個變量時,能夠經過下面的方式:
sum := 0 for i,j := 0,100; i<=j; i++ { sum += i }
循環遍歷array、slice、string、map時,能夠使用range
關鍵字進行控制,range
第一個參數返回的是索引,第二個參數返回的是該索引位置的值:
strings := [] string{"string1", "string2", "string last"} for i,s :=range strings { fmt.Printf("\t%d = %s\n", i, s) }
標準函數定義以下:
func function_name([parameter list]) [return_types] { 函數體 }
函數的參數同C語言同樣,存在值傳遞和引用傳遞,引用傳遞的方式與C語言的指針格式相同:
func swap(x *int, y *int) { var temp int temp = *x /* 保持 x 地址上的值 */ *x = *y /* 將 y 值賦給 x */ *y = temp /* 將 temp 值賦給 y */ }
而實際上若是進行swap,還有更簡單的方式,例以下面是調換a、b兩個變量的值:
a, b = b, a
C語言中通常使用函數指針來指向一個函數,Go中能夠直接將將函數賦值給變量,該變量就是函數:
// 建立一個函數變量 getSquareRoot getSquareRoot := func(x float64) float64 { return math.Sqrt(x) } fmt.Println(getSquareRoot(9)) /* 使用函數 */
所謂閉包,就是將函數自身使用的數據封裝到包中,對外不可見。
參考下面的函數,getSequence
函數返回一個函數,被返回的函數中引用了getSequence
函數的一個局部變量,因此只要被返回的函數存在,那麼getSequence
函中的局部變量i就會存在,這個就是至關於將i變量封到了包中,即閉包。
func getSequence() func() int { i:=0 return func() int { i+=1 // 這裏能夠引用getSequence函數中定義的局部變量 return i } } nextNumber := getSequence() // 建立閉包
Go語言中一個函數能夠返回一個或者多個值,多值返回函數範例:
func swap(x, y string) (string, string) { return y, x }
也能夠對返回值參數進行命名,這樣就能夠在函數體中對返回值參數進行賦值,這個賦值就是至關於設置返回值,範例:
func f(x, y int) (sum int, sub int) { sum = x+y sub = x-y return }
關鍵字defer
容許咱們推遲到函數返回以前執行,若是一個函數存在多個defer
語句,那麼按照後進先出的順序執行,即棧的順序。
例如,下面的代碼指定了2個Defer:
func deferFunc() { fmt.Printf("Hello here is defer funtion\n"); } func testDeferFunc() { fmt.Printf("print 1\n") defer deferFunc() defer func() { // 建立一個匿名函數,並defer執行 fmt.Printf("Hello here is defer function, inner\n") }() fmt.Printf("print 2\n") }
輸出結果爲:
print 1 print 2 Hello here is defer function, inner Hello here is defer funtion