一個網站的用戶管理中,一般用戶都會起一個暱稱,當然用戶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 name, count := 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,在讀這個章節時,只是感覺這個例子有點意思,所以分享給大家 :)