在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ GO/ 7.6 字符串、數(shù)組和切片的應(yīng)用
4.7 strings 和 strconv 包
13.6 啟動(dòng)外部命令和程序
?# 11.4 類(lèi)型判斷:type-switch
12.1 讀取用戶(hù)的輸入
10.6 方法
12.2 文件讀寫(xiě)
13 錯(cuò)誤處理與測(cè)試
9.3 鎖和 sync 包
12.3 文件拷貝
?# 11.7 第一個(gè)例子:使用 Sorter 接口排序
?# 11.5 測(cè)試一個(gè)值是否實(shí)現(xiàn)了某個(gè)接口
6.4 defer 和追蹤
12.10 XML 數(shù)據(jù)格式
13.10 性能調(diào)試:分析并優(yōu)化 Go 程序
?# 11.1 接口是什么
2.2 Go 環(huán)境變量
2.6 安裝目錄清單
2.5 在 Windows 上安裝 Go
11.11 Printf 和反射
1.2 語(yǔ)言的主要特性與發(fā)展的環(huán)境和影響因素
9.0 包(package)
7.4 切片重組(reslice)
13.2 運(yùn)行時(shí)異常和 panic
10.2 使用工廠(chǎng)方法創(chuàng)建結(jié)構(gòu)體實(shí)例
12.8 使用接口的實(shí)際例子:fmt.Fprintf
2.4 在 Mac OS X 上安裝 Go
3.8 Go 性能說(shuō)明
7.2 切片
8.0 Map
3.1 Go 開(kāi)發(fā)環(huán)境的基本要求
5.6 標(biāo)簽與 goto
6.10 使用閉包調(diào)試
9.5 自定義包和可見(jiàn)性
4.3 常量
?# 11.2 接口嵌套接口
6.5 內(nèi)置函數(shù)
前言
10.8 垃圾回收和 SetFinalizer
2.8 Go 解釋器
13.7 Go 中的單元測(cè)試和基準(zhǔn)測(cè)試
6.8 閉包
4.9 指針
13.1 錯(cuò)誤處理
10.1 結(jié)構(gòu)體定義
5.1 if-else 結(jié)構(gòu)
6.6 遞歸函數(shù)
9.9 通過(guò) Git 打包和安裝
2.7 Go 運(yùn)行時(shí)(runtime)
10.7 類(lèi)型的 String() 方法和格式化描述符
3.7 其它工具
9.6 為自定義包使用 godoc
11.12 接口與動(dòng)態(tài)類(lèi)型
13.3 從 panic 中恢復(fù)(Recover)
10.3 使用自定義包中的結(jié)構(gòu)體
11.14 結(jié)構(gòu)體、集合和高階函數(shù)
3.6 生成代碼文檔
9.2 regexp 包
4.1 文件名、關(guān)鍵字與標(biāo)識(shí)符
?# 11.6 使用方法集與接口
7.0 數(shù)組與切片
7.1 聲明和初始化
12.11 用 Gob 傳輸數(shù)據(jù)
5.5 Break 與 continue
1.1 起源與發(fā)展
?# 11 接口(Interfaces)與反射(reflection)
6.9 應(yīng)用閉包:將函數(shù)作為返回值
4.2 Go 程序的基本結(jié)構(gòu)和要素
8.6 將 map 的鍵值對(duì)調(diào)
6.11 計(jì)算函數(shù)執(zhí)行時(shí)間
5.0 控制結(jié)構(gòu)
10.5 匿名字段和內(nèi)嵌結(jié)構(gòu)體
4.6 字符串
3.0 編輯器、集成開(kāi)發(fā)環(huán)境與其它工具
13.8 測(cè)試的具體例子
7.6 字符串、數(shù)組和切片的應(yīng)用
8.4 map 類(lèi)型的切片
3.9 與其它語(yǔ)言進(jìn)行交互
7.3 For-range 結(jié)構(gòu)
9.7 使用 go install 安裝自定義包
6.0 函數(shù)
9.8 自定義包的目錄結(jié)構(gòu)、go install 和 go test
6.3 傳遞變長(zhǎng)參數(shù)
13.9 用(測(cè)試數(shù)據(jù))表驅(qū)動(dòng)測(cè)試
11.9 空接口
8.1 聲明、初始化和 make
6.2 函數(shù)參數(shù)與返回值
9.11 在 Go 程序中使用外部庫(kù)
3.3 調(diào)試器
4.5 基本類(lèi)型和運(yùn)算符
?# 11.8 第二個(gè)例子:讀和寫(xiě)
12.5 用 buffer 讀取文件
總結(jié):Go 中的面向?qū)ο?/span>
11.10 反射包
12.7 用 defer 關(guān)閉文件
9.4 精密計(jì)算和 big 包
4.4 變量
6.1 介紹
13.4 自定義包中的錯(cuò)誤處理和 panicking
12.4 從命令行讀取參數(shù)
9.10 Go 的外部包和項(xiàng)目
8.3 for-range 的配套用法
3.5 格式化代碼
10.4 帶標(biāo)簽的結(jié)構(gòu)體
7.5 切片的復(fù)制與追加
?# 11.3 類(lèi)型斷言:如何檢測(cè)和轉(zhuǎn)換接口變量的類(lèi)型
5.4 for 結(jié)構(gòu)
4.8 時(shí)間和日期
2.3 在 Linux 上安裝 Go
12 讀寫(xiě)數(shù)據(jù)
6.12 通過(guò)內(nèi)存緩存來(lái)提升性能
9.1 標(biāo)準(zhǔn)庫(kù)概述
12.6 用切片讀寫(xiě)文件
10 結(jié)構(gòu)(struct)與方法(method)
8.5 map 的排序
12.9 JSON 數(shù)據(jù)格式
13.5 一種用閉包處理錯(cuò)誤的模式
3.2 編輯器和集成開(kāi)發(fā)環(huán)境
12.12 Go 中的密碼學(xué)
5.2 測(cè)試多返回值函數(shù)的錯(cuò)誤
6.7 將函數(shù)作為參數(shù)
8.2 測(cè)試鍵值對(duì)是否存在及刪除元素
3.4 構(gòu)建并運(yùn)行 Go 程序
2.1 平臺(tái)與架構(gòu)
5.3 switch 結(jié)構(gòu)

7.6 字符串、數(shù)組和切片的應(yīng)用

7.6.1 從字符串生成字節(jié)切片

假設(shè) s 是一個(gè)字符串(本質(zhì)上是一個(gè)字節(jié)數(shù)組),那么就可以直接通過(guò) c := []byte(s) 來(lái)獲取一個(gè)字節(jié)的切片 c。另外,您還可以通過(guò) copy 函數(shù)來(lái)達(dá)到相同的目的:copy(dst []byte, src string)

同樣的,還可以使用 for-range 來(lái)獲得每個(gè)元素(Listing 7.13—for_string.go):

package main

import "fmt"

func main() {
    s := "\u00ff\u754c"
    for i, c := range s {
        fmt.Printf("%d:%c ", i, c)
    }
}

輸出:

0:? 2:界

我們知道,Unicode 字符會(huì)占用 2 個(gè)字節(jié),有些甚至需要 3 個(gè)或者 4 個(gè)字節(jié)來(lái)進(jìn)行表示。如果發(fā)現(xiàn)錯(cuò)誤的 UTF8 字符,則該字符會(huì)被設(shè)置為 U+FFFD 并且索引向前移動(dòng)一個(gè)字節(jié)。和字符串轉(zhuǎn)換一樣,您同樣可以使用 c := []int32(s) 語(yǔ)法,這樣切片中的每個(gè) int 都會(huì)包含對(duì)應(yīng)的 Unicode 代碼,因?yàn)樽址械拿看巫址紩?huì)對(duì)應(yīng)一個(gè)整數(shù)。類(lèi)似的,您也可以將字符串轉(zhuǎn)換為元素類(lèi)型為 rune 的切片:r := []rune(s)。

可以通過(guò)代碼 len([]int32(s)) 來(lái)獲得字符串中字符的數(shù)量,但使用 utf8.RuneCountInString(s) 效率會(huì)更高一點(diǎn)。(參考count_characters.go)

您還可以將一個(gè)字符串追加到某一個(gè)字符數(shù)組的尾部:

var b []byte
var s string
b = append(b, s...)

7.6.2 獲取字符串的某一部分

使用 substr := str[start:end] 可以從字符串 str 獲取到從索引 start 開(kāi)始到 end-1 位置的子字符串。同樣的,str[start:] 則表示獲取從 start 開(kāi)始到 len(str)-1 位置的子字符串。而 str[:end] 表示獲取從 0 開(kāi)始到 end-1 的子字符串。

7.6.3 字符串和切片的內(nèi)存結(jié)構(gòu)

在內(nèi)存中,一個(gè)字符串實(shí)際上是一個(gè)雙字結(jié)構(gòu),即一個(gè)指向?qū)嶋H數(shù)據(jù)的指針和記錄字符串長(zhǎng)度的整數(shù)(見(jiàn)圖 7.4)。因?yàn)橹羔槍?duì)用戶(hù)來(lái)說(shuō)是完全不可見(jiàn),因此我們可以依舊把字符串看做是一個(gè)值類(lèi)型,也就是一個(gè)字符數(shù)組。

字符串 string s = "hello" 和子字符串 t = s[2:3] 在內(nèi)存中的結(jié)構(gòu)可以用下圖表示:

http://wiki.jikexueyuan.com/project/the-way-to-go/images/7.6_fig7.4.png" alt="" />

7.6.4 修改字符串中的某個(gè)字符

Go 語(yǔ)言中的字符串是不可變的,也就是說(shuō) str[index] 這樣的表達(dá)式是不可以被放在等號(hào)左側(cè)的。如果嘗試運(yùn)行 str[i] = 'D' 會(huì)得到錯(cuò)誤:cannot assign to str[i]

因此,您必須先將字符串轉(zhuǎn)換成字節(jié)數(shù)組,然后再通過(guò)修改數(shù)組中的元素值來(lái)達(dá)到修改字符串的目的,最后將字節(jié)數(shù)組轉(zhuǎn)換回字符串格式。

例如,將字符串 "hello" 轉(zhuǎn)換為 "cello":

s := "hello"
c := []byte(s)
c[0] = 'c'
s2 := string(c) // s2 == "cello"

所以,您可以通過(guò)操作切片來(lái)完成對(duì)字符串的操作。

7.6.5 字節(jié)數(shù)組對(duì)比函數(shù)

下面的 Compare 函數(shù)會(huì)返回兩個(gè)字節(jié)數(shù)組字典順序的整數(shù)對(duì)比結(jié)果,即 0 if a == b, -1 if a < b, 1 if a > b。

func Compare(a, b[]byte) int {
    for i:=0; i < len(a) && i < len(b); i++ {
        switch {
        case a[i] > b[i]:
            return 1
        case a[i] < b[i]:
            return -1
        }
    }
    // 數(shù)組的長(zhǎng)度可能不同
    switch {
    case len(a) < len(b):
        return -1
    case len(a) > len(b):
        return 1
    }
    return 0 // 數(shù)組相等
}

7.6.6 搜索及排序切片和數(shù)組

標(biāo)準(zhǔn)庫(kù)提供了 sort 包來(lái)實(shí)現(xiàn)常見(jiàn)的搜索和排序操作。您可以使用 sort 包中的函數(shù) func Ints(a []int) 來(lái)實(shí)現(xiàn)對(duì) int 類(lèi)型的切片排序。例如 sort.Ints(arri),其中變量 arri 就是需要被升序排序的數(shù)組或切片。為了檢查某個(gè)數(shù)組是否已經(jīng)被排序,可以通過(guò)函數(shù) IntsAreSorted(a []int) bool 來(lái)檢查,如果返回 true 則表示已經(jīng)被排序。

類(lèi)似的,可以使用函數(shù) func Float64s(a []float64) 來(lái)排序 float64 的元素,或使用函數(shù) func Strings(a []string) 排序字符串元素。

想要在數(shù)組或切片中搜索一個(gè)元素,該數(shù)組或切片必須先被排序(因?yàn)闃?biāo)準(zhǔn)庫(kù)的搜索算法使用的是二分法)。然后,您就可以使用函數(shù) func SearchInts(a []int, n int) int 進(jìn)行搜索,并返回對(duì)應(yīng)結(jié)果的索引值。

當(dāng)然,還可以搜索 float64 和字符串:

func SearchFloat64s(a []float64, x float64) int
func SearchStrings(a []string, x string) int

您可以通過(guò)查看 官方文檔 來(lái)獲取更詳細(xì)的信息。

這就是如何使用 sort 包的方法,我們會(huì)在第 11.6 節(jié)對(duì)它的細(xì)節(jié)進(jìn)行深入,并實(shí)現(xiàn)一個(gè)屬于我們自己的版本。

7.6.7 append 函數(shù)常見(jiàn)操作

我們?cè)诘?7.5 節(jié)提到的 append 非常有用,它能夠用于各種方面的操作:

  1. 將切片 b 的元素追加到切片 a 之后:a = append(a, b...)
  2. 復(fù)制切片 a 的元素到新的切片 b 上:

      b = make([]T, len(a))
      copy(b, a)
  3. 刪除位于索引 i 的元素:a = append(a[:i], a[i+1:]...)
  4. 切除切片 a 中從索引 i 至 j 位置的元素:a = append(a[:i], a[j:]...)
  5. 為切片 a 擴(kuò)展 j 個(gè)元素長(zhǎng)度:a = append(a, make([]T, j)...)
  6. 在索引 i 的位置插入元素 x:a = append(a[:i], append([]T{x}, a[i:]...)...)
  7. 在索引 i 的位置插入長(zhǎng)度為 j 的新切片:a = append(a[:i], append(make([]T, j), a[i:]...)...)
  8. 在索引 i 的位置插入切片 b 的所有元素:a = append(a[:i], append(b, a[i:]...)...)
  9. 取出位于切片 a 最末尾的元素 x:x, a = a[len(a)-1], a[:len(a)-1]
  10. 將元素 x 追加到切片 a:a = append(a, x)

因此,您可以使用切片和 append 操作來(lái)表示任意可變長(zhǎng)度的序列。

從數(shù)學(xué)的角度來(lái)看,切片相當(dāng)于向量,如果需要的話(huà)可以定義一個(gè)向量作為切片的別名來(lái)進(jìn)行操作。

如果您需要更加完整的方案,可以學(xué)習(xí)一下 Eleanor McHugh 編寫(xiě)的幾個(gè)包:sliceschainlists。

7.6.8 切片和垃圾回收

切片的底層指向一個(gè)數(shù)組,該數(shù)組的實(shí)際容量可能要大于切片所定義的容量。只有在沒(méi)有任何切片指向的時(shí)候,底層的數(shù)組內(nèi)存才會(huì)被釋放,這種特性有時(shí)會(huì)導(dǎo)致程序占用多余的內(nèi)存。

示例 函數(shù) FindDigits 將一個(gè)文件加載到內(nèi)存,然后搜索其中所有的數(shù)字并返回一個(gè)切片。

var digitRegexp = regexp.MustCompile("[0-9]+")

func FindDigits(filename string) []byte {
    b, _ := ioutil.ReadFile(filename)
    return digitRegexp.Find(b)
}

這段代碼可以順利運(yùn)行,但返回的 []byte 指向的底層是整個(gè)文件的數(shù)據(jù)。只要該返回的切片不被釋放,垃圾回收器就不能釋放整個(gè)文件所占用的內(nèi)存。換句話(huà)說(shuō),一點(diǎn)點(diǎn)有用的數(shù)據(jù)卻占用了整個(gè)文件的內(nèi)存。

想要避免這個(gè)問(wèn)題,可以通過(guò)拷貝我們需要的部分到一個(gè)新的切片中:

func FindDigits(filename string) []byte {
   b, _ := ioutil.ReadFile(filename)
   b = digitRegexp.Find(b)
   c := make([]byte, len(b))
   copy(c, b)
   return c
}

事實(shí)上,上面這段代碼只能找到第一個(gè)匹配正則表達(dá)式的數(shù)字串。要想找到所有的數(shù)字,可以嘗試下面這段代碼:

func FindFileDigits(filename string) []byte {
 ? fileBytes, _ := ioutil.ReadFile(filename)
   b := digitRegexp.FindAll(fileBytes, len(fileBytes))
   c := make([]byte, 0)
   for _, bytes := range b {
      c = append(c, bytes...)
   }
   return c
}

練習(xí) 7.12

編寫(xiě)一個(gè)函數(shù),要求其接受兩個(gè)參數(shù),原始字符串 str 和分割索引 i,然后返回兩個(gè)分割后的字符串。

練習(xí) 7.13

假設(shè)有字符串 str,那么 str[len(str)/2:] + str[:len(str)/2] 的結(jié)果是什么?

練習(xí) 7.14

編寫(xiě)一個(gè)程序,要求能夠反轉(zhuǎn)字符串,即將 “Google” 轉(zhuǎn)換成 “elgooG”(提示:使用 []byte 類(lèi)型的切片)。

如果您使用兩個(gè)切片來(lái)實(shí)現(xiàn)反轉(zhuǎn),請(qǐng)?jiān)賴(lài)L試使用一個(gè)切片(提示:使用交換法)。

如果您想要反轉(zhuǎn) Unicode 編碼的字符串,請(qǐng)使用 []int32 類(lèi)型的切片。

練習(xí) 7.15

編寫(xiě)一個(gè)程序,要求能夠遍歷一個(gè)數(shù)組的字符,并將當(dāng)前字符和前一個(gè)字符不相同的字符拷貝至另一個(gè)數(shù)組。

練習(xí) 7.16

編寫(xiě)一個(gè)程序,使用冒泡排序的方法排序一個(gè)包含整數(shù)的切片(算法的定義可參考 維基百科)。

練習(xí) 7.17

在函數(shù)式編程語(yǔ)言中,一個(gè) map-function 是指能夠接受一個(gè)函數(shù)原型和一個(gè)列表,并使用列表中的值依次執(zhí)行函數(shù)原型,公式為:map ( F(), (e1,e2, . . . ,en) ) = ( F(e1), F(e2), ... F(en) )

編寫(xiě)一個(gè)函數(shù) mapFunc 要求接受以下 2 個(gè)參數(shù):

  • 一個(gè)將整數(shù)乘以 10 的函數(shù)
  • 一個(gè)整數(shù)列表

最后返回保存運(yùn)行結(jié)果的整數(shù)列表。

鏈接