GO 基礎知識

文章目錄
   一、常量和變量
   1、常量
        const identifier [type] = value
   2、變量
        2.1 局部變量
             identifier: = value  <==> var identifier [type] = value
        2.2 全局變量
          var identifier [type] = value
        2.3 匿名變量
         " _"
   二、基本數據類型
   1、整型 
         int、uint
   2、浮點
        float32、float64
   3、布爾型
        bool
   4、複數
         complex32
         complex64
   5、字符串
         string
   6、字符串處理(strings 包)
        6.1 包含判斷
             HasPrefix、HasSuffix、Contains、ContainsAny (返回值都是 bool )
        6.2 索引
            Index、LastIndex、IndexRune (返回值都是 int )
        6.3 替換
            Replace (返回一個新的 string)
        6.4 統計
           Count、utf8.RuneCountInString (返回值都是 int )
        6.5 大小寫轉化
           ToLower、ToUpper (返回一個新的 string)
        6.6 修剪
           Trim  (返回一個新的 string)
        6.7 分割
          Splite (返回一個 slice (切片))
        6.8 字符串轉化成字符串切片
          Fields (返回一個 []string 切片)
        6.9 插入
           Join
   7、字符傳與其他類型轉換(strconv包)
       7.1  數字轉化成字符串
           Itoa、FormatFloat、FormatBool
       7.2 數值字符串轉化成對應數值類型
          Atoi、ParseFloat、ParseBool
       7.3 自定義類型轉化成字符串
           Stringer 
   三、基本數據類型擴展
   1、強制類型轉換
         type_name(expression)
   2、自定義類型
        type name struct { }
   3、類型別名
       type 
   4、指針
      4.1 聲明 var name *type
      4.2 nil 指針
      4.3 指針的指針  **ptr
      4.4 指針數組 var ptr []*type
      4.5 傳遞給函數
   四、流程控制語句
   1、條件語句
       if、if-else、if-else if- else
   2、選擇語句
        switch
   3、循環語句
        for、range
   4、延遲語句
        defer
   5、標籤語句
      break、continue、goto

一、常量和變量

1、常量
在GO語言中,常量是指編譯期間就已知,且在執行過程中不會改變的固定值。

const identifier[type] = value  ,其中 type 可省略

批量定義常量

const a,b,c = 1,2,3
const (
		x int  = 1
		y float64 = 2.0
		z  = true
)
fmt.Println(a,b,c,x,y,z)

用於實現枚舉

func enum()  {
	const(
		 a = iota
		 b
		 c
		 d
	)
	fmt.Println(a,b,c,d)  //0、1、2、3   iota有遞增效果,常用於 枚舉
}

常量沒指定類型可以是任意類型。例如: a 可以是浮點也可以是整型。

2、變量

var identifier type 

GO 與其他語言最大的不同在於: 聲明變量時,變量類型放在變量名後面。

批量定義變量

var a,b,c = "string",1,true
var(
	x,y int
	str string
)

2.1 局部變量

func main() {
	a := 1 //等價於 var a = 1
	var b = 1
	fmt.Println(a,b)
}

備註: a := 1這種定義變量的方式只能用於函數體內。局部變量定義了必須使用,否則會報錯。

2.2 全局變量

var z = true
func main() {
	fmt.Println(z)
}

備註: 全局變量定義不限制位置。允許聲明但不使用。

2.3 匿名變量
GO 語言中,函數允許多個返回值。在日常處理中,我們可能會忽略部分返回值的情況,那麼用"_"替代。

二、基本數據類型
1、整型

無符號 uint
有符號 int

整型的運算與主流的編程語言並不差異。這裏不做過多介紹。

2、浮點型
float32 精確到小數點後 7 位
float64 精確到小數點後 15 位

備註: GO語言中沒有 float 這種類型。在運算中推薦使用 float64

3、布爾型

布爾型( bool )的值只可以是 ture 或者 false
支持一元運算符 : !
支持二元運算符 : && 、|| 、==
格式化輸出: %t

4、複數
規定 i = 根號-1,也就是 i^2 = 1
複數 a + bi 的模 = a^2 + b ^2 的算術平方根,其中 a 爲實部位,b 爲虛部
複數支持常規數據運算,實部和虛部都是浮點型
在運算中推薦使用complex64
操作複數的方法在cmath包中

func complexValue()  {
	a := 3.2 + 5i
	b := complex(3.2,5) // b := 3.2 + 5i
	fmt.Printf("複數 a 的實部 = %f, 複數 b 的實部 = %f\n",real(a),real(b))
	fmt.Printf("複數 a 的虛部 = %f, 複數 b 的虛部 = %f\n",imag(a),imag(b))
	fmt.Printf("複數 a 的模 = %f",cmplx.Abs(a))
}

著名歐拉公式 :e^(i+pi) +1 = 0

   fmt.Println(cmplx.Pow(math.E,1i*math.Pi)+1)
   fmt.Println(cmplx.Exp(1i*math.Pi)+1)
   fmt.Printf("%.3f\n",cmplx.Exp(1i*math.Pi)+1)

5、字符串
在 GO 語言中,字符串是一個不可變的 UTF-8 字符序列。一個 ASCII 碼佔用一個字節,其他字符根據需要佔用 2 ~ 4 字節。字符串是一個定長的字節數組。GO 語言默認就是採用 UTF-8 編碼格式進行文件存儲。
5.1 定義一個字符串

var test string = "abc.txt"
str := "abc 中國"

5.2 獲取字符串字節數目和字符數目

str := "cherish中國"
r := []rune(str)
fmt.Printf("字符串 str 的字節數 = %d ,字符數 = %d \n",len(str),len(r))  //  13、9

5.3 訪問字符串中某個字節、某個字符

str := "aA 你 2"
for index := 0; index < len(str); index++{
	fmt.Println(str[index])
}
str[index]返回第 index 個字節的字節值, 0 <= index < len[str]
輸出:
97   //a
65   //A
32   //空格
228  //你
189  //你 
160  //你
32  //空格
50  //2
str := "cherish中國"
for index,value := range str{
	fmt.Printf("index = %d ,value = %c \n",index,value)
}
輸出
index = 0 ,value = c 
index = 1 ,value = h 
index = 2 ,value = e 
index = 3 ,value = r 
index = 4 ,value = i 
index = 5 ,value = s 
index = 6 ,value = h 
index = 7 ,value = 中 
index = 10 ,value =

5.4 解釋字符串和非解釋字符串

解釋字符串: 使用 ""括起來,不能換行,並且能解析轉義字符

非解釋字符串 : 使用 反單引號 括起來,支持換行,反單引號內所有內容直接輸出

5.5 字符串拼接
字符串可以拼接,用 " + " 拼接字符串,但原字符串不會改變

str := "你好"
t := str
str += "golang"
fmt.Printf("str = %s,t = %s",str,t) //str = 你好golang,t = 你好

5.6 字符串之間的比較
在 GO 語言中,字符串是可以使用 “==” 和 “<” 等符號進行比較的,通過比較逐字節的編碼獲得結果。

s := "你"
t := "好"
if s < t {
	fmt.Println(s[0],t[0])  //228 229
	fmt.Println(s[1],t[1])  //189 165
	fmt.Println(s[2],t[2])  //160 189
}
a := "a"
b := "b"
if a < b {
	fmt.Println(a[0],"小於",b[0])  //97 小於 98
}
test := "你好"
test1 := "你好"
if test == test1{
	fmt.Println("兩字符串相等")
}

5.7 字符串修改
在 GO 語言中,字符串內容不能修改,也就不能使用 s[i] 這種方式修改字符串中的 UTF-8 編碼。如果確實要修改,那麼可以將字符串的內容複製到另一個可寫變量中,然後再進行修改。
如果要對字符串中的字節進行修改,則轉換成 []byte 格式
如果要對字符串中的字符進行修改,則轉換成 []rune 格式
轉換過程中,會自動複製數據。

s := "Hello Word!"
b := []byte(s)  //轉換爲 []byte,自動複製數據
b[5] = ','      // 修改 []byte
fmt.Printf("修改字符串中的字節: s = %s \n b = %s\n",s,b)
//輸出
修改字符串中的字節: s = Hello Word! 
b = Hello,Word!


s1 := "Hello 中國!"
r := []rune(s1) //轉化成 []run,自動複製數據
r[6] = '世'      //修改 []run
r[7] = '界'   //修改 []run
fmt.Printf("修改字符串中的字符: s = %s \n b = %s\n",s1,string(r))
//轉化成字符串,又一次複製數據

//輸出
修改字符串中的字符: s = Hello 中國! 
 r = Hello 世界!

備註 : 如果字符串是純 ASCII 字符串,兩種是等價的。

5.8 字符串截取
在日常開發中,我們經常會遇到字符串截取的需求。如果優雅在進行字符串截取呢,這裏涉及到部分 slice 內容。建議初學者後面學到 slice 再往這裏看。
** 5.8.1 字節截取**

test := "你好hello word"
substr := test[3:7]
fmt.Println(substr) // 好h => 截取 區間 [3,7) 之前的字節

5.8.2 字符截取

str := "你好hello word"
r := []rune(str)
fmt.Println(string(r[1:5])) //好hel => 截取區間 [1,5)之間的字符
fmt.Println(string(r[1:])) //好hello word => 截取 index = 1 後面的全部字符
fmt.Println(string(r[:2])) //你好 =>截取 [0,2) 前的全部字符,不包含 index = 2

6、字符串處理(strings包)
對於基本類型來說,字符串所需要執行的操作比較複雜,所以一般語言都會額外封裝一些方法用於處理字符串,GO 語言標準庫中也存在這樣一個名爲 strings的庫。
6.1 包含判斷
HasPrefix(包含前綴)
HasSuffix(包含後綴)
Contains(包含子串)
ContainsAny(匹配更廣泛的內容,甚至可以匹配 Unicode 字符)

func stringsContain(){
	str := "This is an example of a string"
	fmt.Printf("Does the string \"%s\" have prefix %s ?\n",str,"Th")  //true
	fmt.Printf("%t\n",strings.HasPrefix(str,"Th"))
	fmt.Printf("Does the string \"%s\" have suffix %s ?\n",str,"string")
	fmt.Printf("%t\n",strings.HasSuffix(str,"string")) //true
	fmt.Printf("Does the string \"%s\" have contain %s ?\n",str,"example")
	fmt.Printf("%t\n",strings.Contains(str,"string")) //true
}

ContainsContainsAny的區別

func stringContainsAndContainsAny()  {
	fmt.Println(strings.Contains("team","i"))  //false
	fmt.Println(strings.Contains("team"," a & o")) //false
	fmt.Println(strings.Contains("team","")) //true
	fmt.Println(strings.Contains("","")) //true

	fmt.Println()

	fmt.Println(strings.ContainsAny("team","i")) //false
	fmt.Println(strings.ContainsAny("team"," a & o")) //true
	fmt.Println(strings.ContainsAny("team","")) //false
	fmt.Println(strings.ContainsAny("","")) //false
}

備註 :
Contains 底層實現是Index
ContainsAny 底層實現是 IndexAny

6.2 索引
Index :指定字符/串的第一次出現的第一個字符的索引值,如果不存在相應字符串則返回-1
LastIndex :指定字符串最後一次出現位置的第一個字符索引,-1表示不包含特定字符串
IndexRune:如果是非 ASCII 編碼的字符,用此函數對字符進行定位。也是第一次出現第一個字符的索引值。不存在返回-1

func searchStrIndex()  {
	
	indexstr := "你好hello goland好"
	fmt.Println(strings.Index(indexstr,"好")) // => 3,str[3],中文 "你" 佔 3個字節。

     //和 Index 一個意思,都是檢查第一次出現
	fmt.Println(strings.IndexRune(indexstr,/*[]rune(indexstr)[1]*/'好')) // =>3

	// 和 Index 相反,檢查最後一次出現
	lastIndexStr := "hello word"
	fmt.Println(strings.LastIndex(lastIndexStr,"o")) // =>7
}

6.3 替換
func Replace(s, old, new string, n int) string
第一個參數 : 原字符串
第二個參數 : 源字符串中需要被替換的字符串
第三個參數:替換內容
第4個參數:n 表示匹配到第幾個 old,如果 n = -1,表示匹配所有

func stringReplace()  {
	str := "你好世界,這個世界真好。"
    var	newStr string = strings.Replace(str,"世界","地球",1)
	fmt.Println(newStr)  //你好地球,這個世界真好。
}

6.4 統計
Count : 統計指定字符串出現的頻數
utf8.RuneCountInString : 統計指定字符串的字符數量

func stringStatistics()  {
	str := "Golang is cool,right?"
	var many string = "o"
	fmt.Printf("指定字符 \"%s\" 在 字符串 \"%s\"中 出現的頻數爲:%d \n",many,str,strings.Count(str,many))  // 3
	fmt.Printf("字符串 \"%s\"的字符數爲 %d \n",str,len([]rune(str)))  //21
	fmt.Printf("字符串 \"%s\"的字符數爲 %d \n",str,utf8.RuneCountInString(str)) //21
}

6.5 大小寫轉化
ToLower : 將輸入字符串轉化成小寫輸出
ToUpper :將輸入字符串轉化成大寫輸出

func stringToUpperOrToLower()  {

	str := "Hello Golang"
	var lower string = strings.ToLower(str)
	var upper string = strings.ToUpper(str)
	fmt.Printf("\"%s\" lower is \"%s\" and upper is \"%s\"",str,lower,upper)
}

6.6 修剪
Trim 這個函數修剪的是字符串開頭或者結尾的字符,也就是不匹配中間的字符,而且 Trim 函數第二個參數雖然類型是 stirng,但實際上替換時是把字符串轉換成 rune 後來操作的。

func stringTrim()  {
	str := "今天天氣真好"
	fmt.Println(strings.Trim(str,"今")) //天天氣真好
	fmt.Println(strings.Trim(str,"天")) //今天天氣真好
	fmt.Println(strings.Trim(str,"今天")) //氣真好
}

第一句的確裁剪了"今"字,但是第二句的"天"並非字符串首尾,所以不會裁剪,重點在於第三句,可以看到後面的"天"全部被裁剪了,這是因爲Trim函數把第二個參數轉化成了rune類型,進行了逐一匹配–換句話說,實際上"今天"是被分爲兩個字符分別匹配裁剪的,所以只返回了"氣真好"。

6.7 分割
Splite: 返回一個切片(slice)

func stringSplit()  {

	fmt.Println(strings.Split("a,b,c",","))  //[a b c]
	fmt.Printf("%q\n",strings.Split("a,b,c",",")) //["a" "b" "c"]

	fmt.Printf("%q\n",strings.Split("a b c"," ")) //["a" "b" "c"]

	fmt.Printf("%q\n",strings.Split("a b c "," ")) //["a" "b" "c" ""]

}

6.8 ~ 6.9 字符串轉化成字符串切片(Fields)、字符串切片拼接成字符串(Join)

Fields :以連續的空白字符爲分隔符,將 string 切分成多個子串,結果中不包含空白字符本身,空白字符有:\t, \n, \v, \f, \r, ' '

Join:將元素類型爲 stringslice使用分隔符好拼接成一個字符串

func stringInsert()  {

	str := "Hello 世\n界!\tHe\vl\flo!"
	var slice []string = strings.Fields(str)
	fmt.Printf("%q\n",slice)
    var result string = strings.Join(slice,"")
   fmt.Println(result)
}
輸出:
["Hello" "世" "界!" "He" "l" "lo!"]
Hello世界!Hello!

7、字符串和其他類型轉換(strconv包)
一般來說,幾乎所有類型都可以被轉化成字符串,單反過來要把字符串轉換成其他類型就不一定能夠成功。前面有講到runestring類型的轉換。下面看下數字和字符串之間的轉換。

7.1 數字轉化成字符串

Itoa整型、FormatFloat浮點型、FormatBool布爾型 轉化成字符串

//1.整型數字到字符串
convint := strconv.Itoa(10)
fmt.Println(convint,reflect.TypeOf(convint)) // 10 string

//2.浮點性數字到字符串
convfloat := strconv.FormatFloat(3.23,'g',3,64)
fmt.Println(convfloat,reflect.TypeOf(convfloat)) //3.23 string

//3.布爾型到字符串
convbool := strconv.FormatBool(true)
fmt.Println(convbool,reflect.TypeOf(convbool)) // true string

7.2 字符串轉化成數字
Atoi整型、ParseFloat浮點型、ParseBool布爾型 字符串轉化成對應基本數據類型

//4.整型字符串到整型
if result,err := strconv.Atoi("10");err != nil{
   fmt.Println(err)
}else {
	fmt.Println(result,reflect.TypeOf(result))  //10 int
}
//5.布爾類型字符串到布爾類型
if result,err := strconv.ParseBool("1");err != nil{
  fmt.Println(err)
}else {
   fmt.Println(result,reflect.TypeOf(result)) //true bool
}
//6.浮點類型字符串到浮點類型
if result,err := strconv.ParseFloat("3.24",64);err != nil{
	fmt.Println(err)
}else {
	fmt.Println(result,reflect.TypeOf(result)) //3.24 float64
}

備註 : 上面的reflect.TypeOf是個反射api。返回對應數據類型。

7.3 自定義類型轉化成字符串
實現 Stringer 接口,實現 String() string 方法 即可.

type Student struct {
	Name string
}

func (s Student) String() string {
	return  "name is " + s.Name
}

func cusTypeConvString()  {
   jack := new(Student)
   jack.Name = "jack"
   fmt.Println(jack.String())  // name is jack
}

三、基本數據類型擴展

3.1 強制類型轉換
類型轉換用於將一種數據類型的變量轉化成良一中類型的變量。GO 語言的類型轉化基本格式: type_name(expression)
在做強制類型轉換時,需要注意數據長度被截短而發生的數據精度丟失(比如浮點轉化成整數) 和 值溢出 (值超過轉換的目標類型的值範圍時) 問題。

func typeExpression()  {
	sum := 11
	count := 3
	mean := float32(sum) / float32(count)
	mean1 := sum / count
	fmt.Printf("mean = %.2f \n",mean)  //mean = 3.67 
	fmt.Printf("mean1 = %d \n",mean1)   //mean1 = 3 
}

3.2 自定義類型
在 GO 語言中,自定義類型實際上與結構體有關。這裏暫不介紹關於結構體過多內容的說明。上面已經有一個 Student 結構體。
type name struct { //TO DO }
3.3 類型別名
type 給已知的數據類型取另外一個名字。

func typeAlternativeName()  {
	type 字符串 string
	var b 字符串
	b = "這是中文。"
	fmt.Println(b)  //  這是中文。
	a := "這也是一箇中文"
	//fmt.Println(a+b)
	fmt.Println(string(b)+a) //這是中文。這也是一箇中文
}

注意 : 上面例子中,注意註釋的那一句,在編譯器中這種寫法是錯誤的,因爲類型別名與原有類型是兩種類型,不能直接操作,需要進行類型轉換

3.4 指針

3.4.1 聲明
指針變量都是指向一個內存位置,每個內存位置都有其定義的地址,可以使用 & 運算符來訪問它,這個運算符表示內存中的地址。
指針是一個變量,其值是另外一個變量的地址,即存儲器位置的直接地址。類似變量和常量一樣,必須先聲明一個指針,然後才能使用它來存儲任何變量地址。指針的變量聲明一般格式爲: var name *type
所有指針的值的實際數據類型都是相同的,他表示內存地址的長十六進制數。
使用指針基本上是三個步驟:
1. 定義一個指針變量
2. 將一個變量的地址賦值給一個指針
3. 最後訪問指針變量中可用地址的值

GO 語言中通過使用一元運算符* 來取得指向指針存儲的內存地址所對應的值(指針的格式化標識符爲 %p)。GO語言指針不支持指針運算,不支持 -> 運算符

func pointer()  {
	a := 20
	pointer := &a
	fmt.Printf("a 的地址: %x \n",&a)  //a 的地址: c0000b4008 
	fmt.Printf("pointer 的地址: %x \n",pointer) //pointer 的地址: c0000b4008 
	fmt.Printf("pointer 的值: %d\n",*pointer) //pointer 的值: 20
}

3.4.2 nil 指針
GO 語言編譯器爲指針變量分配一個 nil值,以防指針沒有確切的地址分配,這是在變量聲明的時候完成的。指定爲 nil 值 的指針稱爲 nil 指針,nil 指針 是在幾個標準庫中定義的值爲 0 的常量。在大多數操作系統中,程序不允許訪問地址 0 處的內存,因爲改內存是由操作系統保留的。然而,存儲器地址 0 具有特殊意義,他表示指針不打算指向可訪問的存儲器的位置。如果指針包含 nil 值,則假設他不指向任何對象。要檢查是否爲 nil 指針,可以使用 if 語句

if(ptr != nil)
if(ptr == nil)

對於一個空指針的反向引用是不合法的,並且會使程序 crash

var ptr *int = nil
*ptr = 10

3.4.3 指針的指針
直接上兩個例子說明下就好理解

func pointerOfThePointer()  {
	var a *int
	ap := &a
	if a == nil {
		fmt.Println("a 爲 nil 指針")
	}
	fmt.Printf("a --> nil : %x\n",a)  //0
	fmt.Printf("ap --> a : %x \n",ap)
	fmt.Printf("ap -> a --> nil(指針 ap 指向的指針 a 的內存地址):%x \n",*ap) //0
	fmt.Printf("&ap --> ap(表示 ap 在內存中的地址):%x\n",&ap)
}
func doublePointer()  {
	a := 10
	ap := &a
	app := &ap
	fmt.Printf("a = %d \n",a)  //10
	fmt.Printf("ap = %x \n",ap) //10在存儲器位置上直接地址
	fmt.Printf("*ap = %d \n",*ap) // 10
	fmt.Printf("app = %x \n",app) // 變量 ap 在存儲器位置上的直接地址
	fmt.Printf("*app = %x \n",*app) // 10 在存儲器上的直接地址
	fmt.Printf("**ap = %d \n",**app) //10
}
輸出如下:
a = 10 
ap = c000016050 
*ap = 10 
app = c00000e028 
*app = c000016050 
**ap = 10 

3.4.5 指針數組
雖然我們還未介紹到 GO 數組,但是並不妨礙理解指針數組的概念。

func pointerArrays()  {

	a := [3]int{10,20,30}
	var ptr [3]*int
	for index := 0; index < 3;index++ {
		ptr[index] = &a[index]
		fmt.Printf("a[%d]的地址:%x\n",index,ptr[index])
	}
	for index := 0 ;index < 3;index++ {
		fmt.Printf("a[%d]的值爲:%d\n",index,*ptr[index])
	}
}
輸出結果:
a[0]的地址:c00001c0e0
a[1]的地址:c00001c0e8
a[2]的地址:c00001c0f0
a[0]的值爲:10
a[1]的值爲:20
a[2]的值爲:30

3.4.5傳遞給函數
GO 語言允許傳遞指針到函數中,只需要將函數參數聲明爲指針類型。

func swap(a *int,b *int)  {
	 temp := *a
	 *a = *b
	 *b = temp
}

func paramsPointer()  {
	a := 100
	b := 200
	swap(&a,&b)
	fmt.Printf("a = %d,b = %d \n",a,b) //a = 200,b = 100
}

四、流程控制語句
1、條件語句
if、if-else、if-else if- else
跟大多數語言一樣,我們要說的就是 GO 語言特有的點: if 語句可以有一個子語句,子語句只能有一個表達式。if 後面的括號可以省略。

func conditionStatement()  {
	
	if a := 10; a < 20 {
		fmt.Println("a 小於 20")
	}else{
		fmt.Printf("%d 大於或等於 20 \n",a)
	}

	if a,b := 10,20; a< b {
		fmt.Println("a < b")
	}else {
		fmt.Println("a >= b")
	}
    /* 編譯錯誤。初始化子語句只能有一個表達式
	if a := 10; b := 10; a < b {
		fmt.Println("a < b")
	}else{
		fmt.Println("a >= b")	
	}*/
}

2、選擇語句
switch
跟大多數語言一樣,這裏還是講特殊點: break可省略,fallthrough 關鍵字可以把當前case控制權移交給下一個case語句判斷。switch同樣和if一樣擁有初始化子語句。
表達式 switch : switch 後面可以沒有表達式,case 後可以跟表達式。

var x interface{}
func switchStatement()  {

	//1.表達式switch: switch後面沒有語句;case可以多個語句,語句之間用","分割,跟 fallthrough 意思一致
	marks := 95
	switch {
	case marks >= 90:
		fmt.Println("優秀")
	case marks >= 80,marks >= 70:
		fmt.Println("良好")
	default:
		fmt.Println("一般")
	}

	//2.類型switch: 跟主流編程語言一致。但是 break 可以省略不寫。
      x  = 10
	switch dataType := x.(type){
	case int:
		fmt.Printf("int 類型 %T \n",dataType)
	case float64:
		fmt.Printf("flaot64 類型 %T \n",dataType)
	case bool:
		fmt.Printf("bool 類型 %T \n",dataType)
	case string:
		fmt.Printf("string 類型 %T \n",dataType)
	case nil:
		fmt.Printf("nil 類型 %T \n",dataType)
	default:
		fmt.Println("未知類型")
	}
}

3、循環語句
for、range
for 語句跟主流編程語言保持一致,只不過 for 後面的語句括號省略
這裏主要是 range: 這貨非常強大,其作用類似於迭代器,用於輪詢數組或者切片的每一個元素,也可以用於輪詢字符串中的每一個字符,以及字典中的每一個鍵值對,甚至還可以持續讀取一個通道類型值中的元素

func rangeStatement()  {

	//1. 字符串
	fmt.Println("range 字符串")
	str := "I Love 中國"
	for index,char := range str{
		fmt.Printf("str[%d] = %c\n",index,char)
	}

	fmt.Println()

	fmt.Println("range 數組或切片")
	//2.數組或切片
	arrays := [5]int{1,2,3,4,5}
	for index,value := range arrays{
		fmt.Printf("arrays[%d] = %d\n",index,value)
	}

	fmt.Println()

	fmt.Println("range 字典")
	//3.字典(映射)
	dictionary := map[string]string{"name":"jack","country":"china"}
	for key,value := range dictionary{
		fmt.Printf("dictionray[%s] = %s \n",key,value)
	}
}

輸出結果

range 字符串
str[0] = I
str[1] =  
str[2] = L
str[3] = o
str[4] = v
str[5] = e
str[6] =  
str[7] = 中
str[10] =range 數組或切片
arrays[0] = 1
arrays[1] = 2
arrays[2] = 3
arrays[3] = 4
arrays[4] = 5

range 字典
dictionray[name] = jack 
dictionray[country] = china 

備註: GO 沒有 三目運算符,沒有 do-while

4、延遲語句
defer: 用於延遲調用指定函數,defer 關鍵字只能出現在函數內部
兩大特點
4.1 只有當 defer 語句全部執行,defer 所在函數纔算真正結束
4.2 當函數中 有 defer 語句時,需要等待所有 defer 語句執行完畢,纔會執行 return 語句
defer 一般用於回收資源,清理收尾等工作
defer 其實是一個棧,遵循先入後出(後進先出),簡單來說,當一個函數內部出現多個 defer 語句時,最後面的 defer 語句最先執行

func deferStatement()  {
	for index := 0;index < 5;index++ {
		defer printStatement(index)
	}
}

func printStatement(i int)  {
	fmt.Println(i)
}

輸出結果:
4
3
2
1
0

5、標籤語句
GO 語言中,可以給 for、switch 等流程控制代碼打上一個標籤,配置標籤標識符可以方便跳轉到某一個地方繼續執行,有助於提高編程效率。標籤名字區分大小寫,爲了提高閱讀性,建議標籤使用大寫字母和數字組合標籤可以標記任何語句,未使用的標籤會引發錯誤

break(跳出for循環)、continue(僅能用於for循環)、goto(只能在同一個函數中跳轉)

下面列舉三個方法簡單解釋下三個標籤語句

5.1 break

func breakTagStatement()  {
	LOOP1:
		for  {
			x := 1
			switch  {
			case x > 0:
				fmt.Println("A")
				break LOOP1
			case x == 1:
				fmt.Println("B")
			default:
				fmt.Println("C")
			}
		}
}
輸出結果:
A

5.2 contiune

func contiuneTagStatement()  {
	LOOP1:
		for index := 0; index <= 5;index++ {
			switch  {
			case index > 0:
				fmt.Println("A")
				continue LOOP1
			case index == 1:
				fmt.Println("B")
			default:
				fmt.Println("C")
			}
			fmt.Printf("index = %d \n",index)
		}
}
輸出結果:
C
index = 0 
A
A
A
A
A

5.3 goto

func gotoTagStatement()  {
	var i int
	for  {
		fmt.Println(i)
		i++
		if i > 2 {
			goto BREAK
		}
	}
	BREAK:
		fmt.Println("break")
}
輸出結果:
0
1
2
break

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章