[TOC] # 本篇前瞻 好的,現在你已經來到一個新的小結,在這裡你將學習到go語言的重要內容,習得go 25個關鍵字中的12個:var, const, if, else, switch, case, default, fallthrough, for, break, goto, continue, ...
目錄
本篇前瞻
好的,現在你已經來到一個新的小結,在這裡你將學習到go語言的重要內容,習得go 25個關鍵字中的12個:var, const, if, else, switch, case, default, fallthrough, for, break, goto, continue,即在順序結構學習var,const,在分支結構中學習if, else, switch, case, default, fallthrough,在迴圈結構中學習for, break, goto, continue。另外你最好註冊一個Leetcode賬號.
Leetcode習題9
讓我們再來看下這個例子,這個是一個比較好的例子,裡面包含了順序,分支以及迴圈的所有控制結構
題目描述
給你一個整數 x
,如果 x
是一個迴文整數,返回 true
;否則,返回 false
。
迴文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。
代碼編寫
func isPalindrome(x int) bool {
if (x < 0) { //分支結構
return false
}
x64 := x //順序結構
px64 := 0
for x64 != 0 { //迴圈結構
px64 = px64*10 + x64%10 // 順序結構
x64 /= 10
}
return px64 == x
}
你在這個道題目中能看到所有的控制結構:順序結構,分支結構,迴圈機構
控制結構
順序結構(Sequence)
聲明和賦值
在順序結構中聲明和賦值是很重要的
var可以聲明一個變數,而const則聲明一個常量
package main
import "fmt"
func main() {
var i1 int //聲明變數,預設值為0
var i2 int = 1 //聲明變數,初始化為1
i3 := 2 //這是最常用的聲明和初始化手段
fmt.Println(i1, i2, i3)
i4 := i2 + i3 //使用運算表達式賦值
i3 *= i4 //使用運算表達式賦值
fmt.Println(i3, i4)
const ci1 int = 13 //聲明常量,無法
fmt.Println(ci1)
x, y, z := 100, 101, 102 //多返回值
fmt.Println(x, y, z) //列印結果
}
輸出:
0 1 2
6 3
13
100 101 102
這裡僅僅舉例了整形int的聲明
多返回值賦值
x,y,z := 0,1,2
go語言允許這樣多返回值賦值賦值方式,再挖個坑,原因會在介紹函數時說明一下。
運算符
算術運算符
++ | -- | |||
---|---|---|---|---|
自增1 | 自減1 | |||
+= | -= | *= | /= | %= |
自增 | 自減 | 自乘 | 自除 | 自模,取餘 |
+ | - | * | / | % |
加法 | 減法 | 乘法 | 除法 | 模,取餘 |
註意: 例如如3/2 在整型中是整除即3/2=1,在浮點型是3.0/2.0=1.5,模運算智能用於整數
位運算符
<< | >> | & | | | ^ |
---|---|---|---|---|
左移 | 右移 | 與 | 或 | 亦或 |
<<= | >>= | &= | |= | ^= |
自左移 | 自右移 | 自與 | 自或 | 自亦或 |
位運算符幾乎我們這篇實用的編程用不到,但是這個概念也很重要,電腦底層事實上是這樣工作的,這裡在挖個坑,後面會介紹位運算的相關leetcode題目,你會看到它的威力。
邏輯運算
&& | || | == | != | ! |
---|---|---|---|---|
與 | 或 | 相等 | 不等於 | 非 |
>= | <= | > | < | |
大於等於 | 小於等於 | 大於 | 小於 |
這些會在分支語句中大放異彩。
分支結構
if 語句
if 語句有if,if-else以及if-else if-else結構,如下所示:
package main
import "fmt"
func main() {
var input int
fmt.Printf("請輸入分數:")
fmt.Scanf("%d", &input)
if input < 60 { //if
fmt.Println("1.不合格")
}
if input < 60 { //if-else
fmt.Println("2.不合格")
} else{
fmt.Println("2.合格")
}
if input < 60 {//if-else if-else
fmt.Println("3.不合格")
} else if input < 70 {
fmt.Println("3.合格")
} else if input < 85 {
fmt.Println("3.良好")
} else {
fmt.Println("3.優秀")
}
}
結果如下:
請輸入分數:59
1.不合格
2.不合格
3.不合格
switch 語句
事實上switch 語句比if語句更為強大,在有多個分支時更為符合go語言的風格,完整代碼如下:
package main
import "fmt"
func main() {
var i int
fmt.Printf("請輸入分數:")
fmt.Scanf("%d\n", &i)
switch {
case i < 60: //單個邏輯表達式
fmt.Println("不合格")
case i < 70:
fmt.Println("合格")
case i < 85:
fmt.Println("良好")
default:
fmt.Println("優秀")
}
var c byte
fmt.Printf("請輸入等級:")
fmt.Scanf("%c\n", &c)
switch c {
case 'E', 'e': //可以有多個選擇
fmt.Println("1.不合格")
case 'D', 'd':
fmt.Println("1.基本合格")
case 'C', 'c':
fmt.Println("1.合格")
case 'B', 'b':
fmt.Println("1.良好")
case 'A', 'a':
fmt.Println("1.優秀")
default:
fmt.Println("1.錯誤的輸入")
}
switch {
case c == 'E', c == 'e': //可以有多個表達式
fmt.Println("2.不合格")
case c == 'D', c == 'd':
fmt.Println("2.基本合格")
case c == 'C', c == 'c':
fmt.Println("2.合格")
case c == 'B', c == 'b':
fmt.Println("2.良好")
case c == 'A', c == 'a':
fmt.Println("2.優秀")
default:
fmt.Println("2.錯誤的輸入")
}
switch {
case c == 'E':
fmt.Println("3.不合格")
fallthrough //fallthrough會執行下一個case區塊
case c == 'e':
fmt.Println("3.真的不合格")
case c == 'D', c == 'd':
fmt.Println("3.基本合格")
case c == 'C', c == 'c':
fmt.Println("3.合格")
case c == 'B', c == 'b':
fmt.Println("3.良好")
case c == 'A', c == 'a':
fmt.Println("3.優秀")
default:
fmt.Println("3.錯誤的輸入")
}
var in interface{} = i
switch data := in.(type) { //類型推斷
case int:
fmt.Printf("int: %v\n", data)
case uint:
fmt.Printf("uint: %v\n", data)
default:
fmt.Printf("type: %T\n", data)
}
}
結果如下:
請輸入分數:90
優秀
請輸入等級:E
1.不合格
2.不合格
3.不合格
3.真的不合格
int: 90
邏輯表達式
註意case可以是單個或多個邏輯表達式
switch {
case c == 'E', c == 'e': //可以有多個表達式
fmt.Println("2.不合格")。
case c == 'D', c == 'd':
fmt.Println("2.基本合格")
case c == 'C', c == 'c':
fmt.Println("2.合格")
case c == 'B', c == 'b':
fmt.Println("2.良好")
case c == 'A', c == 'a':
fmt.Println("2.優秀")
default:
fmt.Println("2.錯誤的輸入")
}
fallthrough
fallthrough會執行下一個case區塊
switch {
case c == 'E':
fmt.Println("3.不合格")
fallthrough //fallthrough會執行下一個case區塊
case c == 'e':
fmt.Println("3.真的不合格")
case c == 'D', c == 'd':
fmt.Println("3.基本合格")
case c == 'C', c == 'c':
fmt.Println("3.合格")
case c == 'B', c == 'b':
fmt.Println("3.良好")
case c == 'A', c == 'a':
fmt.Println("3.優秀")
default:
fmt.Println("3.錯誤的輸入")
}
類型推斷
這個是一個強大的方式,它可以用於推斷go語言的介面的類型,不過現在只能簡單那介紹一下,你可以將interface{}可以表達任何類型
var in interface{} = i
switch data := in.(type) { //類型推斷
case int:
fmt.Printf("int: %v\n", data)
case uint:
fmt.Printf("uint: %v\n", data)
default:
fmt.Printf("type: %T\n", data)
}
迴圈語句
迴圈語句只有for
package main
import "fmt"
func main() {
var input int
fmt.Printf("請輸入分數(0-5):")
fmt.Scanf("%d", &input)
for i := 0; i < 5; i++ { //正常的for
fmt.Println("loop1:", i)
if i < 2 {
continue //跳過本次執行
}
if i == input {
fmt.Println("loop1: break") //跳出本層迴圈
break
}
}
i := 0
Loop:
for i < 5 { //去掉;的for迴圈
fmt.Println("loop2:", i)
for j := 0; j < 5; j++ {
if j == input {
fmt.Println("loop2: break Loop") //跳出Loop標記的迴圈
break Loop
}
if j == 1 {
break //跳出本層迴圈
}
}
i++
}
i = 0
for ; i < 5; i++ { //空缺一個元素並帶有;的for迴圈
fmt.Println("loop3:", i)
for j := 0; j < 5; j++ {
if j < 2 {
continue
}
if j == input {
goto Exit //跳出到Exit
}
}
}
return
Exit:
fmt.Println("loop3: Exit")
}
結果如下:
請輸入分數(0-5):1
loop1: 0
loop1: 1
loop1: 2
loop1: 3
loop1: 4
loop2: 0
loop2: break Loop
loop3: 0
loop3: 1
loop3: 2
loop3: 3
loop3: 4
請輸入分數(0-5):2
loop1: 0
loop1: 1
loop1: 2
loop1: break
loop2: 0
loop2: 1
loop2: 2
loop2: 3
loop2: 4
loop3: 0
loop3: Exit
continue
跳過本次迴圈
break
沒有加標簽的就是跳過本層迴圈
加標簽的就是跳過被標簽標記的迴圈
goto
跳到被標簽標記的迴圈,使用goto在處理一些同意的錯誤或者統一的出口而降低代碼的冗餘,增加代碼可讀性。這裡挖個坑,這裡會在go-etl展示goto的魅力
註意:很多書籍指出goto會破環代碼結構,降低代碼可讀性,那是因為這些書籍講述使用goto的場景錯了。
Leetcode習題69
我們以leetcode習題開始,而現在有以一道Leetcode習題結束
題目描述
給你一個非負整數 x
,計算並返回 x
的 算術平方根 。
由於返回類型是整數,結果只保留 整數部分 ,小數部分將被 捨去 。
註意:不允許使用任何內置指數函數和算符,例如 pow(x, 0.5)
或者 x ** 0.5
。
題目分析
這道題會比Leetcode習題1更加困難些,這次數據範圍是int32
的非負整數範圍,由於不能使用指數函數和算符,為此,在這裡我們需要使用二分法,即通過二分[a,b]
(mid = a + (b-a)/2
, 第一輪a=0,b=x
)去獲取mid=x/2
,如果mid*mid<x
那麼此時二分[a,mid-1]
,反之二分[mid+1,b]
, 這樣不斷二分下去直到 mid*mid=x
或者a<b
。好的,這樣我們獲得瞭解題思路,但是還有個問題,選擇y的數據類型是什麼,如果選擇int32
,那麼相乘必然超過int32
, 為此我們必須選擇int64
,註意:在Leetcode習題9中得出了結論,int
是64位的,所以不用改為int64
。
代碼編寫
func mySqrt(x int) int {
a, b := 0, x //多返回值賦值
for a <= b { // 無;結構的for
mid := a + (b-a)/2 //二分區間
if mid*mid == x { //if語句
return mid
}
if mid*mid < x { //if-else語句
a = mid + 1 //選擇較大的區間
} else {
b = mid - 1 //選擇較小的區間
}
}
return b
}
本篇小結
恭喜你已經完成了所有控制結構的學習,你以及知道了所有控制結構用到的保留字和註意點。另外,通過Leetcode習題69和Leetcode習題9,你已經知道在編程時選擇數據類型的重要性,並且練習了所有控制結構。這裡的相關代碼放在go語言學習的go-base/3中,請下載後進行實際的練習
註意:之後的Leetcode題目解答以及使用工具的編程中,數據類型的選擇以及控制結構的應用是非常重要的,也是最為基礎的。
下篇預告
go語言複合類型