做爲一門高級語言,Go一樣提供了流程控制的支持。在瞭解了基礎結構以後,繼續學習Go的流程控制,裏面涉及到的基礎結構的內容還能對其有更多的瞭解。git
說流程控制以前先說一下interface,由於後續在流程控制中會穿插着對interface的使用。github
interface是一切類型的基類型,相似於Java中的基類Obejct
,全部的結構都是interface的實現,由於interface基類型沒有定義任何的函數,因此其餘任何結構都認爲是interface的實現。固然,也能夠本身定義interface本身去實現相應的函數,這個下期面向對象的時候會詳細解釋。這裏先簡單說明interface做爲基類型時的使用。微信
在Java中,全部的類型都是Object的子類,因此聲明對象時能夠將對象的類型聲明爲Object,在賦值時給一個子類型,在Go中一樣能夠,但僅限於針對interface聲明的使用(仍是會牽涉到面向對象的東西),也就是說,聲明時能夠將變量聲明爲interface類型,賦值時給一個其餘基礎類型的值,這是最簡單的interface做爲基類型的使用。app
var hello interface{} = "hello world" fmt.Println(hello)
例子中聲明hello時,聲明的類型是interface{}類型,並非string類型,可是賦值時給的是string類型,說明hello實際類型仍是string類型。具體的類型轉換下面會詳細說明。less
Go中的if-else結構的用戶與Java中的特別的相似,僅僅區別在二者的語法上面,Go的語法爲:函數
if 條件1 { ... } else if 條件2 && 條件3 { ... } else { ... }
Go對語法的要求沒有Java那麼嚴格,對於括號能夠帶,也能夠不帶。一樣的,Go也支持&&
、||
、!
這樣的運算符進行多個條件的關聯判斷學習
func max(a, b int) (max int) { if a > b { max = a } else if a == b { max = a } else { max = b } return }
斷言在Go中是一種類型轉換的語法,可否方便的進行類型的轉換。Go語言中簡單的斷言語法爲 value := element.(type)
設計
//value := element.(type) //type爲要轉換的類型 var hello interface{} = "helloworld" fmt.Println(hello.(string)) fmt.Println(hello.(int))//該行會報錯,由於hello實際類型是string類型
稍微不注意,直接轉換的話就會出現異常,因此通常不推薦使用簡單的語法,而是用高級語法 value, ok := element.(type)
,這也是在if-else結構中講解的緣由。code
// value, ok := element.(type) //type爲要轉換的類型,ok爲是否成功轉換,類型爲bool,value爲實際轉換的值 var hello interface{} = "helloworld" helloS, ok := hello.(string) if ok { fmt.Println("hello tranfer successfully : ", helloS) } else { fmt.Println("hello transfer failed") }
使用高級語法能保證在運行的時候不會出現錯誤,保證程序的持續執行,這是比較推薦的作法。orm
map斷言是map的一種高級用法。
//map的斷言 // value, ok := m[key] //這裏的OK再也不是簡單的成功或者失敗,理解成是否存在更合適 var m = make(map[string]interface{})//建立map的方式,具體make的用法後續會講解 m["key1"] = "value1" value1, ok := m["key1"] if ok { fmt.Println("map m contain 'key1' ", value1) } else { fmt.Println("map m contain 'key1'") }
map在斷言的使用上好像是天生支持似的,不須要進行Contains函數的校驗等,直接使用,平時在代碼中使用的也是很是多。簡直不要太好用。
switch感受像是if-else的高級版,一樣是進行條件判斷的結構,不一樣的條件執行不一樣的語句。語法相似Java,Java中只能使用byte、int、short、char和string,在Go中可沒有這些限制。 從上至下的判斷,直到找到匹配的case或者執行default語句,case結尾也不須要break進行跳出流程操做,執行完自動跳出。相反,若是想執行下一個case的話,須要使用fallthrough
關鍵字進行下沉操做, 這時候下一條case的條件將被忽略。
switch value1 { //大括號必須與switch保持一行 case value1: ... case value2, value3://多個條件使用逗號隔開 ... default://沒有符合的條件執行默認 ... }
語法規定 switch後跟的value1能夠是任意類型(甚至是不寫),可是case後的條件必須和switch後的value保持相同類型
grade := 10 switch grade { //case code < 60://code爲int類型,不能使用code < 60做爲case條件 case 10: fmt.Println("不及格") case 70: fmt.Println("及格") default: fmt.Println("無效的分數") } //用於類型斷言 switch hello.(type) { case string: fmt.Println("hello is string") case int: fmt.Println("hello is int") default: fmt.Println("hello is unknown type") } switch {//直接判斷case case a < b: fmt.Println("a less than b") fallthrough //緊接着執行下一個case,不須要進行判斷 case a > b: fmt.Println("a bigger than b") }
說到循環、重複執行等首先想到的就是for,Go一樣提供了支持,相對於Java,Go中for的使用更靈活。 一樣的,想跳出for循環時使用break
關鍵字。
//語法一 for init;條件;賦值{//左側大括號必須與for同行 ... } //語法二 for 條件 {//左側大括號必須與for同行 ... } //語法三 //這是個死循環 for {//左側大括號必須與for同行 ... } //語法四 for index, value := range slice/array/map {//range是關鍵字 ... }
上手就是一個排序來介紹最基本的for結構
a := []int{1, 3, 9, 4, 1, 4, 6, 132, 1, 29, 43, 55, 89, 46} for i := 0; i < len(a); i++ {//len爲Go內置函數 for j := i + 1; j < len(a); j++ { if a[i] > a[j] { a[i], a[j] = a[j], a[i] } } } fmt.Println(a)//結果:[1 1 1 3 4 4 6 9 29 43 46 55 89 132]
只寫條件的for循環,相似Java中的while
var i = 0 for i < len(a) { fmt.Print(a[i]," ") i++ }//結果: 1 1 1 3 4 4 6 9 29 43 46 55 89 132
死循環寫法更簡單了,不過須要注意使用break進行跳出,不然電腦就該嗡嗡嗡~響不停了
i = 0 for{ if i < len(a) { fmt.Print(a[i], " ") i++ } else { break } }//結果: 1 1 1 3 4 4 6 9 29 43 46 55 89 132
最牛的語法四就是爲slice和array使用的,能遍歷全部的集合。當遍歷slice和array時,index指的是其中的索引位置;遍歷map時指的就是key了。請看下面的例子
for index, value := range a { fmt.Printf("index: %d, value: %d \n", index, value) } /* 結果: index: 0, value: 1 index: 1, value: 1 index: 2, value: 1 index: 3, value: 3 index: 4, value: 4 index: 5, value: 4 index: 6, value: 6 index: 7, value: 9 index: 8, value: 29 index: 9, value: 43 index: 10, value: 46 index: 11, value: 55 index: 12, value: 89 index: 13, value: 132 */ m := map[string]string{} m["hello"] = "world" m["hey"] = "bye" for key, value := range m { fmt.Printf("key: %s, value: %s \n", key, value) } /* 結果: key: hello, value: world key: hey, value: bye */
select 第一眼看到可能會想到SQL中的選擇,可是它也是Go中的一個流程控制關鍵字。
select的使用主要是結合channel來使用,因此這裏要是講解channels會設計到不少東西,咱們後期會作詳細的講解,這裏先作select的介紹。
select的語法跟switch相似,用於選擇合適的條件進行執行相應的邏輯,但牽涉到channel,因此select中的case都是對channel的操做,只能是往channel中讀或者寫。
select { case channel讀操做: ... case channel寫操做: ... default: ... }
注意點:
channel包含讀和寫兩種操做,case中必須包含一種操做
case的執行是無序的、隨機的,select會執行任意一個可執行的case
沒有可執行的case時會執行default,沒有default的話就會阻塞,等待可執行的channel
下面是一個簡單的例子實現,先不要深究內容含義,瞭解select語法便可
c := make(chan int, 1) select { case c <- 1: fmt.Println("push into channel") case <-c: fmt.Println("get from channel") default: fmt.Println("default") } //結果:push into channel
不要懷疑標題,標題就是三個英文點,這裏要說一下這三個點的問題,以此來解釋一下爲何在使用fmt.Println()和fmt.Printf()函數時使用逗號將參數隔開的問題。
咱們先看一下fmt.Println()和fmt.Printf()的源碼
// Println formats using the default formats for its operands and writes to standard output. // Spaces are always added between operands and a newline is appended. // It returns the number of bytes written and any write error encountered. func Println(a ...interface{}) (n int, err error) { return Fprintln(os.Stdout, a...) } // Printf formats according to a format specifier and writes to standard output. // It returns the number of bytes written and any write error encountered. func Printf(format string, a ...interface{}) (n int, err error) { return Fprintf(os.Stdout, format, a...) }
這裏看到Println()和Printf()這兩個函數其實就一個入參,爲何我能用逗號分隔從而給多個參數呢?
緣由是這樣的,a ...interface{}
這個實際上是slice的一個特殊用法,說明這定義的是一個可變參數,能夠接收不定數量的統一類型的參數,定義爲...interfaec{}就能夠接收不定數量的任意基礎類型。定義可變參數時的語法就是在類型前面加上這三個點,這裏使用interface就說明能夠接收任何類型
想使用這可變參數的語法也很簡單,能夠將其做爲slice使用,也能夠繼續將其做爲可變參數使用。使用可變參數的語法就是在定義的後面加上這三個點。下面看例子
func main(){ definedThreeDot("jack", "rose", "tom", "jerry")//定義多個參數來使用可變參數 } func definedThreeDot(source ...string) {//定義可變參數,定義時在類型前面加上三個點 useThreeDot(source...)//將可變參數做爲可變參數使用,使用時在定義後面加上三個點 useThreeDotAsSlice(source)//將可變參數做爲slice使用 } func useThreeDotAsSlice(ss []string) {//定義slice來接收可變參數 fmt.Println(ss)//直接打印slice } func useThreeDot(ss ...string) {//定義可變參數,定義時在類型前面加上三個點 for index, s := range ss {//做爲slice來遍歷可變參數 fmt.Printf("index : %d, value : %s \n", index, s)//index和s都做爲可變參數來使用 } } /* 結果: index : 0, value : jack index : 1, value : rose index : 2, value : tom index : 3, value : jerry [jack rose tom jerry] * /
Go 中的流程控制大體上就這麼多,平時項目中使用的也是很是多的,特別是對便利集合時,很是的方便。相信你親自體驗後也會讚不絕口的。
同時也順帶解釋了一下可變參數,結合着slice和流程控制也能對這個可變參數有一個更深的瞭解。
源碼能夠經過'github.com/souyunkutech/gosample'獲取。
首發微信公衆號:Go技術棧,ID:GoStack
版權歸做者全部,任何形式轉載請聯繫做者。
做者:搜雲庫技術團隊 出處:https://gostack.souyunku.com/2019/04/29/if-for-switch-select