Go筆記-運算符和流程控制

運算符

  • b = b + a 能夠寫成b += a
  • 除以浮點數0.0會獲得+Inf
a := 1.0 - 1.0
	fmt.Println("Hello, ", 9.0/a) // Hello,  +Inf
  • 對於整數和浮點數,可使用一元運算符 ++(遞增)和 --(遞減),但只能用於後綴。i++ 帶有 ++ 和 -- 的只能做爲語句,而非表達式,所以 n = i++ 這種寫法是無效的,其它像 f(i++) 或者 a[i]=b[i++] 這些能夠用於 C、C++ 和 Java 中的寫法在 Go 中也是不容許的.sql

  • 在運算時 溢出 不會產生錯誤,Go 會簡單地將超出位數拋棄。若是你須要範圍無限大的整數或者有理數(意味着只被限制於計算機內存),你可使用標準庫中的 big 包,該包提供了相似 big.Int 和 big.Rat 這樣的類型。數組

  • %取模運算符的符號和被取模數的符號老是一致的,所以-5%3和-5%-3結果都是-2.閉包

流程控制

條件語句if-else

i := 4
if i < 0 {
	fmt.Println("<0")
} else if i == 0 {
	fmt.Println("=0")
} else {
	fmt.Println(">0")
}
  • 條件語句不須要使用括號將條件包含起來();
  • 不管語句體內有幾條語句,花括號{}都是必須存在的;
  • 左花括號{必須與if或者else處於同一行;
  • 在if以後,條件語句以前,能夠添加變量初始化語句,使用;間隔;
if i, j := 0, 0; i <= 0 {
		fmt.Println(i, j)
	}

i, j只在if-else中有效,若是以前有i,j定義,則會覆蓋oop

選擇語句switch

i := 7
switch i {
case 0:
	fmt.Println(0)
case 1:
	fmt.Println(1)
case 2:
	fallthrough // 向下執行
case 3:
	fmt.Println(3)
case 4, 5, 6:
	fmt.Println("4,5,6")
default:
	fmt.Println("default")
}
  • 左花括號{必須與switch處於同一行;編碼

  • 條件表達式不限制爲常量或者整數;指針

str := "a"
	switch str {
	case "a":
		fmt.Println("a")
	case "b":
		fmt.Println("b")
	}
  • 單個case中,能夠出現多個結果選項;code

    case 4,5,6對象

  • 與C語言等規則相反,Go語言不須要用break來明確退出一個case;默認退出索引

  • 只有在case中明確添加fallthrough關鍵字,纔會繼續執行緊跟的下一個case,fallthrough再也不判斷條件內存

  • 能夠不設定switch以後的條件表達式,在此種狀況下,整個switch結構與多個if...else...的邏輯做用等同。

i := 0
	switch {
	case 0 <= i && i <= 3:
		fmt.Println("0~3")
	case i > 3:
		fmt.Println(">3")
	}
  • 帶初始化語句

    switch i, j := 9, 10; {
    case i == 1 && j == 10:
    	fmt.Println("no")
    case i == 9 && j == 10:
    	fmt.Println("yes")
    }
  • fallthrough示例

i := 0
switch i {
case 0:
	fmt.Print("0 ")
	fallthrough
case 1:
	fmt.Print("1")
}
輸出:0 1

switch 與類型判斷:(database.sql/convert.go:convertAssign())

var src interface{}

src = "123"

switch s := src.(type) {
case string:
	fmt.Printf("1:type:%T, value:%v\n", s, s)
	fmt.Println(strconv.ParseInt(s, 10, 64))
default:
	fmt.Printf("2:type:%T, value:%v", s, s)
}

循環語句for

  • 只支持for,不支持while,do-while
  • 左花括號{必須與for處於同一行。
  • 特別注意,永遠不要在循環體內修改計數器,這在任何語言中都是很是差的實踐!
  • Go語言中的for循環與C語言同樣,都容許在循環條件中定義和初始化變量,惟一的區別是,Go語言不支持以逗號爲間隔的多個賦值語句,必須使用平行賦值的方式來初始化多個變量
for i, n := 0, 10; i < n; i++ {
		fmt.Printf("%d\t", i)
	}
  • 支持continue和break來控制循環
for i, n := 0, 10; ; i++ {
		fmt.Printf("%d\t", i)
		if i >= n {
			break
		}
	}

loop:
	for i := 0; ; i++ {
		fmt.Printf("for1 :%d ", i)
		for j := 0; j <= i; j++ {
			if i == 1 && j == 1 {
				break loop
			}
		}
	}
  • 無限循環
for {
}
  • 只有判斷條件,至關於while
for i < 10 {
}
  • 循環變量Unicode字符
for i, v := range "漢字\x80" {
		fmt.Printf("character %#U starts at byte position %d\n", v, i)
	}

輸出:

character U+6C49 '漢' starts at byte position 0
character U+5B57 '字' starts at byte position 3
character U+FFFD '�' starts at byte position 6

錯誤的編碼(上例中的\x80)會佔用一個字節,使用U+FFFD來代替

注意變量i第二次是3,而不是1

當for i:=range 「sss」時,i表明的是下標。

  • Go沒有逗號操做符,而且++和--是語句而不是表達式。所以,若是你想在for中運行多個變量,你須要使用並行賦值(儘管這樣會阻礙使用++和--)
for i, j := 0, 5; i < j; i, j = i+1, j-1 {
	fmt.Println(i, j)
}
  • 循環遍歷修改數組

當使用下面的方式修改數組時: items := [...]int{10, 20, 30, 40, 50} for _, item := range items { item *= 2 } fmt.Println(items)

items的元素沒有被修改。由於item是元素的拷貝而不是指針。 使用下面的方式可修改: items := [...]int{10, 20, 30, 40, 50} for i, _ := range items { items[i] *= 2 }

- for中變量的做用域 for i := 0; i < 3; i++ { for i := 0; i < 3; i++ { fmt.Println(i) } }

內層for也聲明瞭i,這說明這個i屏蔽了外層的i,因此最後輸出的是9個數。

for range

var x = []int{5, 12, 32}

	// 使用值和索引
	for i, v := range x {
		fmt.Println(i, "=>", v)
	}
	
	// 只使用索引
	for v := range x {
		fmt.Println(v) // v是索引,0-3
	}
	
	// 只使用值
	for _, v := range x {
		fmt.Println(v)
	}
	
	// 不使用循環中的值
	for _ = range x {
		fmt.Println(80)
	}
	
	// 不使用循環中的值,須要1.4之後版本
	for range x {
		fmt.Println(90)
	}

range會複製對象

a := [3]int{0, 1, 2}
// Q: range時內存中是否是有一個原數組和一個拷貝的數組
for i, v := range a {
	if i == 0 {
		a[1], a[2] = 999, 999 // 修改原數組
		fmt.Printf("%v, %p \n", a, &a)
	}
	a[i] = v + 100 // 此時v是range以前原數組複製的值
	fmt.Printf("%v, %p \n", a, &a)
}

fmt.Printf("%v, %p \n", a, &a)

輸出:

[0 999 999], 0x20819e020 
[100 999 999], 0x20819e020 
[100 101 999], 0x20819e020 
[100 101 102], 0x20819e020 
[100 101 102], 0x20819e020

i和v的值在range時就被拷貝了,而引用類型不會複製底層數據:

s := []int{1, 2, 3, 4, 5}
for i, v := range s { // 複製 struct slice {pointer, len, cap}
	if i == 0 {
		s = s[:3]  // 對slice的修改不會影響range,修改的是range外的s
		s[2] = 100 // 對底層數據的修改,這裏的s也是range外的
	}
	fmt.Println(i, v)
}
fmt.Println(s)

輸出:

0 1
1 2
2 100
3 4
4 5
[1 2 100]

另外兩種引用類型 map, channel 是指針包裝,而不像 slice 是 struct。

for和閉包

arr := []int{12, 34, 56}
	for _, v := range arr {
		go func() {
			fmt.Println(v)
		}()
	}
	time.Sleep(5 * time.Second)

上面輸出都是56.緣由不明。

使用下面的語句能夠達到遍歷的目的:

arr := []int{12, 34, 56}
	for _, v := range arr {
		go func(v int) {
			fmt.Println(v)
		}(v)
	}
	time.Sleep(5 * time.Second)

goto語句

func myfunc() {
	i := 0
HERE:
	fmt.Println(i)
	i++
	if i < 10 {
		goto HERE
	}
}

若是您必須使用 goto,應當只使用正序的標籤(標籤位於 goto 語句以後),但注意標籤和 goto 語句之間不能出現定義新變量的語句,不然會致使編譯失敗。

// compile error goto2.go:8: goto TARGET jumps over declaration of b at goto2.go:8
package main

import "fmt"

func main() {
		a := 1
		goto TARGET // compile error
		b := 9
	TARGET:  
		b += a
		fmt.Printf("a is %v *** b is %v", a, b)
}

break和continue

break可用於 for, switch, select, 而 continue 只能用於 for.

相關文章
相關標籤/搜索