Go字典懒棉、字符串

1 字典

map是一種較為特殊的數(shù)據(jù)結(jié)構(gòu)穗慕,在任何一種編程語言中都可以看見他的身影享钞,它是一種鍵值對結(jié)構(gòu),通過給定的key可以快速獲得對應(yīng)的value栗竖。

1.1 如何定義字典

package main

import "fmt"

var m1 map[string]int//簡單可以放在函數(shù)外
func main() {
    m2 := make(map[int]interface{}, 100)//必須函數(shù)內(nèi)
    m3 := map[string]string{
        "name": "james",
        "age":  "35",
    }//必須函數(shù)內(nèi)
    fmt.Println(m2[1])
    fmt.Println(m3["name"])
    fmt.Println("Hello")
}

在定義字典時不需要為其指定容量,因為map是可以動態(tài)增長的狐肢,但是在可以預(yù)知map容量的情況下,為了提高程序的效率也最好提前標明程序的容量份名。需要注意的是,不能使用不能比較的元素作為字典的key妓美,例如數(shù)組,切片等壶栋。而value可以是任意類型的辰如,如果使用interface{}作為value類型,那么就可以接受各種類型的值贵试,只不過在具體使用的時候需要使用類型斷言來判斷類型。

1.2 字典操作

向字典中放入元素也非常簡單

package main

import "fmt"

func main() {
    m3 := map[string]string{
        "name": "james",
        "age":  "35",
    }
    fmt.Println(m3["name"])
    m3["key1"] = "v1"
    m3["key2"] = "v2"
    m3["key3"] = "v3"

    fmt.Println(m3["key2"])
}

你可以動手試一下毙玻,如果插入的兩個元素key相同會發(fā)生什么桑滩?
與數(shù)組和切片一樣幌氮,我們可以使用len來獲取字典的長度戳吝。

package main

import "fmt"

func main() {
    m3 := map[string]string{
        "name": "james",
        "age":  "35",
    }

    m3["key1"] = "v1"
    m3["key2"] = "v2"
    m3["key3"] = "v3"

    fmt.Println(len(m3))
}

在有些情況下浩销,我們不能確定鍵值對是否存在塘雳,或者當前value存儲的是否就是空值,go語言中我們可以通過下面這種方式很簡便的進行判斷普筹。

package main

import "fmt"

func main() {
    m3 := map[string]string{
        "name": "james",
        "age":  "35",
    }

    value0, ok0 := m3["name"]

    fmt.Println(ok0)
    fmt.Println("v=" + value0)

    value1, ok1 := m3["n"]

    fmt.Println(ok1)
    fmt.Println("v=" + value1)

    value2 := m3["age"]
    fmt.Println("v=" + value2)
    //if支持1個初始化語句, 初始化語句和判斷條件以分號分隔
    if value, ok := m3["name"]; ok { //條件為真败明,指向{}語句
        fmt.Println("if包含下:" + value)
    }

}

上面這段代碼的作用就是如果當前字典中存在key為name的字符串則取出對應(yīng)的value,并返回true太防,否則返回false妻顶。

對于一個已經(jīng)存在的字典,我們?nèi)绾螌ζ溥M行遍歷呢蜒车?可以使用下面這種方式:

package main

import "fmt"

func main() {
    m3 := map[string]string{
        "name": "james",
        "age":  "35",
    }
    for key, value := range m3 {
        fmt.Println("key: ", key, " value: ", value)
    }

}

如果多運行幾次上面的這段程序會發(fā)現(xiàn)每次的輸出順序并不相同讳嘱,對于一個字典來說其默認是無序的,那么我們是否可以通過一些方式使其有序呢酿愧?你可以動手嘗試一下沥潭。(提示:可以通過切片來做哦)

如果已經(jīng)存在與字典中的值已經(jīng)沒有作用了,我們想將其刪除怎么辦呢嬉挡?可以使用go的內(nèi)置函數(shù)delete來實現(xiàn)钝鸽。

package main

import "fmt"

func main() {
    m3 := map[string]string{
        "name": "james",
        "age":  "35",
        "key1": "----",
    }
    for key, value := range m3 {
        fmt.Println("key: ", key, " value: ", value)
    }
    delete(m3, "key1")

    _, ok := m3["key1"]
    fmt.Println(ok)
}

除了上面的一些簡單操作,我們還可以聲明值類型為切片的字典以及字典類型的切片等等庞钢,你可以動手試試看拔恰。

不僅如此我們還可以將函數(shù)作為值類型存入到字典中。

package main

import "fmt"

func main() {
    m := make(map[string]func(a, b int) int)
    m["add"] = func(a, b int) int {
        return a + b
    }
    m["multi"] = func(a, b int) int {
        return a * b
    }
    m["devide"] = func(a, b int) int {
        return a / b
    }
    fmt.Println(m["add"](3, 2))
    fmt.Println(m["multi"](3, 2))
    fmt.Println(m["devide"](3, 2))
}

2 字符串

字符串應(yīng)該可以說是所有編程語言中最為常用的一種數(shù)據(jù)類型基括,接下來我們就一起探索下go語言中對于字符串的常用操作方式颜懊。

2.1 字符串定義

字符串是一種值類型,在創(chuàng)建字符串之后其值是不可變的阱穗,也就是說下面這樣操作是不允許的饭冬。

package main

func main() {
    s := "hello"
    s[0] = 'T'
}

編譯器會提示cannot assign to s[0]。在C語言中字符串是通過\0來標識字符串的結(jié)束揪阶,而go語言中是通過長度來標識字符串是否結(jié)束的昌抠。

如果我們想要修改一個字符串的內(nèi)容,我們可以將其轉(zhuǎn)換為字節(jié)切片鲁僚,再將其轉(zhuǎn)換為字符串炊苫,但是也同樣需要重新分配內(nèi)存。

package main

import "fmt"

func main() {
    s := "hello"

    fmt.Println(s) //gello
    b := []byte(s)
    b[0] = 'g'
    s1 := ""
    s1 = string(b)
    fmt.Println(s1) //gello
}

與其他數(shù)據(jù)類型一樣也可以通過len函數(shù)來獲取字符串長度冰沙。

package main

import "fmt"

func main() {
    s := "hello"

    fmt.Println(len(s)) //gello

}

但是如果字符串中包含中文就不能直接使用byte切片對其進行操作侨艾,go語言中我們可以通過這種方式

package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    s := "hello你好中國"
    fmt.Println(len(s))                    //17
    fmt.Println(utf8.RuneCountInString(s)) //9

    b := []byte(s)
    fmt.Println(len(b))
    for i := 0; i < len(b); i++ {
        fmt.Printf("%c", b[i])
    } //hello?? ?¥???-???
    fmt.Println()

    r := []rune(s)//和utf8.RuneCountInString同
    fmt.Println(len(r))
    for i := 0; i < len(r); i++ {
        fmt.Printf("%c", r[i])
    } //hello你好中國
}

在go語言中字符串都是以utf-8的編碼格式進行存儲的,所以每個中文占三個字節(jié)加上hello的5個字節(jié)所以長度為17拓挥,如果我們通過utf8.RuneCountInString函數(shù)獲得的包含中文的字符串長度則與我們的直覺相符合唠梨。而且由于中文對于每個單獨的字節(jié)來說是不可打印的,所以可以看到很多奇怪的輸出侥啤,但是將字符串轉(zhuǎn)為rune切片則沒有問題当叭。

2.2 strings包

strings包提供了許多操作字符串的函數(shù)茬故。在這里你可以看到都包含哪些函數(shù)https://golang.org/pkg/strings/

下面演示幾個例子:

package main

import (
    "fmt"
    "strings"
)

func main() {
    var str string = "This is an example of a string"
    //判斷字符串是否以Th開頭
    fmt.Printf("%t\n", strings.HasPrefix(str, "Th"))
    //判斷字符串是否以aa結(jié)尾
    fmt.Printf("%t\n", strings.HasSuffix(str, "aa"))
    //判斷字符串是否包含an子串
    fmt.Printf("%t\n", strings.Contains(str, "an"))
}

2.3 strconv包

strconv包實現(xiàn)了基本數(shù)據(jù)類型與字符串之間的轉(zhuǎn)換蚁鳖。在這里你可以看到都包含哪些函數(shù)https://golang.org/pkg/strconv/磺芭。

下面演示幾個例子:

package main

import (
    "fmt"
    "strconv"
)

func main() {
    i, err := strconv.Atoi("-42") //將字符串轉(zhuǎn)為int類型
    s := strconv.Itoa(-42)        //將int類型轉(zhuǎn)為字符串
    fmt.Println(i, err, s)

}

若轉(zhuǎn)換失敗則返回對應(yīng)的error值。

2.4 字符串拼接

2.4.1 Sprintf

除了以上的操作外醉箕,字符串拼接也是很常用的一種操作钾腺,在go語言中有多種方式可以實現(xiàn)字符串的拼接,但是每個方式的效率并不相同讥裤,下面就對這幾種方法進行對比放棒。(關(guān)于測試的內(nèi)容會放在后面的章節(jié)進行講解,這里大家只要知道這些拼接方式即可)

1.Sprintf

//BenchmarkSprintf_test.go
package main

import (
    "fmt"
    "testing"
)

func BenchmarkSprintf(b *testing.B) {
    b.ResetTimer()
    for idx := 0; idx < b.N; idx++ {
        var s string
        for i := 0; i < numbers; i++ {
            s = fmt.Sprintf("%v%v", s, i)
        }
    }
    b.StopTimer()
}

2.4.2 +拼接

BenchmarkStringAdd_test.go

package main

import (
    "strconv"
    "testing"
)
const numbers = 100
func BenchmarkStringAdd(b *testing.B) {
    b.ResetTimer()
    for idx := 0; idx < b.N; idx++ {
        var s string
        for i := 0; i < numbers; i++ {
            s += strconv.Itoa(i)
        }
    }
    b.StopTimer()
}

2.4.3 bytes.Buffer

BenchmarkBytesBuf_test.go

package main

import (
    "bytes"
    "strconv"
    "testing"
)
const numbers = 100
func BenchmarkBytesBuf(b *testing.B) {
    b.ResetTimer()
    for idx := 0; idx < b.N; idx++ {
        var buf bytes.Buffer
        for i := 0; i < numbers; i++ {
            buf.WriteString(strconv.Itoa(i))
        }
        _ = buf.String()
    }
    b.StopTimer()
}

2.4.4 strings.Builder拼接

BenchmarkStringBuilder_test.go

package main

import (
    "strconv"
    "strings"
    "testing"
)

const numbers = 100

func BenchmarkStringBuilder(b *testing.B) {
    b.ResetTimer()
    for idx := 0; idx < b.N; idx++ {
        var builder strings.Builder
        for i := 0; i < numbers; i++ {
            builder.WriteString(strconv.Itoa(i))
        }
        _ = builder.String()
    }
    b.StopTimer()
}

2.4.5 對比

被認為是基準測試坞琴,通過 "go test" 命令哨查,加上 -bench flag 來執(zhí)行。多個基準測試按照順序運行剧辐。

$ go test  -bench.
goos: windows
goarch: amd64
BenchmarkBytesBuf-12             1072903              1105 ns/op
BenchmarkSprintf-12                71346             16485 ns/op
BenchmarkStringAdd-12             209205              5777 ns/op
BenchmarkStringBuilder-12        1370254               879 ns/op
PASS
ok      _/C_/Users/learn/go/GoHello     7.943s

可以看到通過strings.Builder拼接字符串是最高效的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末邮府,一起剝皮案震驚了整個濱河市荧关,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌褂傀,老刑警劉巖忍啤,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異仙辟,居然都是意外死亡同波,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門叠国,熙熙樓的掌柜王于貴愁眉苦臉地迎上來未檩,“玉大人,你說我怎么就攤上這事粟焊≡┙疲” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵项棠,是天一觀的道長悲雳。 經(jīng)常有香客問我,道長香追,這世上最難降的妖魔是什么合瓢? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮透典,結(jié)果婚禮上晴楔,老公的妹妹穿的比我還像新娘顿苇。我一直安慰自己,他們只是感情好滥崩,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布岖圈。 她就那樣靜靜地躺著,像睡著了一般钙皮。 火紅的嫁衣襯著肌膚如雪蜂科。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天短条,我揣著相機與錄音导匣,去河邊找鬼。 笑死茸时,一個胖子當著我的面吹牛贡定,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播可都,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼缓待,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了渠牲?” 一聲冷哼從身側(cè)響起旋炒,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎签杈,沒想到半個月后瘫镇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡答姥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年铣除,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鹦付。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡尚粘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出睁壁,到底是詐尸還是另有隱情背苦,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布潘明,位于F島的核電站行剂,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏钳降。R本人自食惡果不足惜厚宰,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铲觉,春花似錦澈蝙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盐杂,卻和暖如春逗载,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背链烈。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工厉斟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人强衡。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓擦秽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親漩勤。 傳聞我的和親對象是個殘疾皇子感挥,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容