Go語言學習:01-基本語法

基本語法

源文件構成

最簡單的一個go程序:golang

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

Go源程序由幾部分構成:數組

  1. package用於包聲明:package main表示一個可獨立執行的程序,** Go應用程序必須包含名爲main的包**,若是無main包,那麼編譯器會提示"cannot run non-main package";
  2. import用於導入須要引用的外部包, import "fmt"告訴 Go 編譯器這個程序須要使用 fmt 包;
  3. func main()是程序的主函數,通常來講都是在啓動後第一個執行的函數(若是有init() 函數則會先執行init函數);
  4. 標識符由字母、數字和下劃線構成,首字符必須是字母或者下劃線,Go語言經過標識符的首字母標識是否能夠導出到外部:
  • 當標識符以大寫字母開頭,那麼這個標識符就能夠被外部包引用,也稱爲導出,相似於面嚮對象語言中的public
  • 當標識符以小寫字母開頭,則對包外是不可見的,相似於面嚮對象語言中的protected

數據類型

變量分爲值類型和引用類型:閉包

  • 值類型:int、float、bool 和 string 這些基本類型都屬於值類型,使用這些類型的變量直接指向內存中的值;
  • 引用類型:引用類型的變量保存的是被引用對象的地址,也就是C語言中的指針。

基本類型變量

Go語言中的變量類型基本涵蓋了C語言的基本類型,同時增長指定長度的類型,例如:int八、uint八、int1六、uint1六、int3二、uint32等。ide

Go語言中有多種定義變量的方法,分別介紹:函數

  1. 定義變量時指定數據類型,格式var v_name v_type,範例:
var varInPackage1 int			// 本地變量,沒有賦初始值
var varInPackage2 int = 10		// 本地變量賦初始值爲10
var VarInPackage int = 20		// 全局變量賦初始值爲20
  1. 省略類型,讓編譯器根據右值推測數據類型:
var intVar = 10
var stringVar = "String"
  1. 省略var關鍵字,經過:=進行賦值,這種定義只能位於函數體內,用於建立局部變量,因此必須確保變量沒有被定義過:
intVar := 10
intVar1, strVar = 20, "StrValue"	// 同時定義兩個變量
a, _ = 10, 20						// 忽略第二個參數
  1. 因式分解方式,通常用於聲明全局變量:
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 	// 注意方括號爲空

建立切片

切片有幾種建立方法:

  1. 與特定數組綁定,建立方法爲:
var slice1 []type = arr1[start:end]  // arr1爲已經建立的數組或者切片
  1. 直接建立切片:
var x = []int{2, 3, 5, 7, 11}	// 建立一個長度爲5的切片
  1. 使用make建立切片:
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
)

String

Go語言提供了strings包,專門處理string類型的數據。
例如:

  • strings.Contains()判斷字符串中是否包含特定字符串;
  • strings.Index()返回特定字符串在指定字符串中的位置;
  • ...

文檔能夠參考:https://studygolang.com/pkgdoc

Map

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

if語句格式與C語言相比,只不過測試表達式不帶括號(也能夠帶括號),其餘與C語言相同:

if 測試表達式 {
	/* 在布爾表達式爲 true 時執行 */
} else {
	/* 在布爾表達式爲 false 時執行 */
}

switch

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"  
}

ifswitch還有另一種寫法,支持接受一個初始化參數,格式以下:

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容許咱們推遲到函數返回以前執行,若是一個函數存在多個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
相關文章
相關標籤/搜索