讀《Go併發編程實戰》第4章 流程控制方式

       一個網站的用戶管理中,一般用戶都會起一個暱稱,當然用戶A和用戶B的暱稱有可能相同,我們就使用類型爲map[string]int的集合來表示,其中string代表用戶暱稱、int表示暱稱相同的人數。

       集合數據內容爲:{"chen":20,   "chen長":10,   "春風":5,   "龍ge":13,   "where你are":7}。


§問題1. 從這個集合中找出只包含中文的用戶暱稱的計數信息

    上面集合中只有用戶暱稱爲“春風”的元素滿足條件,其它像“龍ge”、“chen長”、“where你are”都不是隻包含中文。像看程序實現:

users := map[string]int{"chen": 20, "chen長": 10, "春風": 5, "龍ge": 13, "where你are": 7}
var targetCount map[string]int = make(map[string]int)

for name, count := range users {
    matched := true
    for _, v := range name {
        if v < '\u4e00' || v > '\u9fbf' {
            matched = false
            break
        }
    }
    if matched {
        targetCount[name] = count
    }
}
fmt.Println(targetCount)

解釋一下:

第一層for循環遍歷users集合,得到暱稱(name)和計數(count ):

for namecount := range users{

      // ......

}

第二層循環遍歷暱稱name字符串中的每個字符,並判斷是否有非中文字符:

for _, v := range name{

      if v <'\u4e00' || v > '\u9fbf' // 該範圍下的字符爲非中文字符

      }

}

【備註】:

    這裏由變量matched充當了標誌,當出現非中文字符時,matched被賦爲false,並使用break中止第二層循環,然後判斷該name是否僅爲中文,若是則添加進入targetCountw集合中。


運行結果爲:map[春風:5]


§問題2. 從這個集合中找出只包含中文的用戶暱稱的計數信息,但發現第一個非全中文的用戶暱稱的時候就停止查找

    這裏涉及到map類型的特性問題,當使用for進行遍歷users集合時,順序會出現不確定性,即第一個暱稱有可能是“chen”,也有可能是“春風”,也有可能是“龍ge”,總之是不確定的。

    假設第一個暱稱是“chen長”時,程序發現它是非全中文的暱稱,這時整個程序需要結束。

for name, count := range users {
    matched := true
    for _, v := range name {
        if v < '\u4e00' || v > '\u9fbf' {
            matched = false
            break
        }
    }
    if !matched {
        break
    } else {
        targetCount[name] = count
    }
}
fmt.Println(targetCount)

    這個程序實現與上面基本是大同小異,不同之處在於第一層循環中的matched判斷。

    假設在第一層for循環中,第一次取到的暱稱name爲“龍ge”,此時第二層for循環中會逐個字符地查看“龍ge”這個字符串,當程序發現“龍ge”是非全中文時,matched標誌被置爲false,同時跑出第二層循環,然後在第一層循環中問:“取到的暱稱‘龍ge’是否爲全中文?”,結果不是,於是按照題目要求就break掉程序並時跳出第一層循環。


    這裏如果您多運行一下程序,就會發現結果有可能是不同的,有時爲map[],有時爲map[春風:5]


§問題3. 不使用輔助標識(如上例中的matched)解決§問題2.

    作者這裏是讓您學習break Label這個東東,所以這裏直接引用作者原話了:“我們之前說過,break語句可以與標記(Label)語句一起配合使用。

L:
    for name, count := range users {
        for _, v := range name {
            if v < '\u4e00' || v > '\u9fbf' {
                 break L
            }
        }
        targetCount[name] = count
    }

該程序與§問題2程序功能是相同的,只是把標誌matched移除掉了。


    一條標記語句可以成爲goto語句、break語句和contiune語句的目標。標記語句中的標記只是一個標識符,它可以被置在任何語句的左邊以作爲這個語句的標籤。標記和被標記的語句之間需要用冒號“:”來分隔,即如下所示:

L:

     for name, count := range users{

          // .....

     }

    需要注意的是,標記L也是一個標識符,那麼當它在未被使用的時候同樣也會報告編譯錯誤。那麼怎麼使用呢?一種方法就是讓它成爲break的目標,即上面示例中的break L。

    標籤L代碼塊包含了第一層for循環,第一層for循環包含了第二層for循環,所以當break L時,它是中止整個標籤L代碼塊,所以這裏會中止兩層for循環。


 對比“§問題2”和“§問題3”的兩個代碼實現,“§問題3”的代碼更簡潔一些。


§問題4.  還是解決問題1的事情,只不過要求使用continue語句,即從這個集合中找出只包含中文的用戶暱稱的計數信息

由於這裏沒有更多的知識點,所以引用原文:

    實際上,Go語言中的continue語句只能在for語句中使用。continue語句會使直接包含它的那個for循環直接進入下一次迭代,換言之,本次迭代不會執行該continue語句後面那些語句(它們被跳過了)。

for name, count := range users {
    matched := true
    for _, v := range name {
        if v < '\u4e00' || v > '\u9fbf' {
            matched = false
            break
        }
    }

    if !matched {
       continue
    }
    targetCount[name] = count
}

或者

L:
    for name,count := range users{
        for _, v := range name{
            if r < '\u4e00' || r > '\u9fbf'{
                continue L
            }
        }
        targetCount[name] = count
    }


OK,在讀這個章節時,只是感覺這個例子有點意思,所以分享給大家 :)

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