make loop

This commit is contained in:
chai2010
2015-12-18 14:49:31 +08:00
parent 9fde1ff772
commit f9ac065e47
106 changed files with 725 additions and 725 deletions

View File

@@ -1,3 +1,3 @@
## 3.3.
## 3.3.
TODO

View File

@@ -1,17 +1,17 @@
## 3.4. 爾型
## 3.4. 爾型
一個爾類型的值隻有兩種 true 和 false. if 和 for 語句的條件部分都是爾類型的值, 且 == 和 < 等比較操作也會產生佈爾型的值. 一元操作符 `!` 對應邏輯非操作, 因此 `!true` 的值爲 `false`, 也可以 `(!true==false)==true`, 雖然表達方式不一樣, 不過我們一般會用簡潔的爾表達式, 就像用 x 來表示 `x==true`.
一個爾類型的值隻有兩種 true 和 false. if 和 for 語句的條件部分都是爾類型的值, 且 == 和 < 等比較操作也會産生布爾型的值. 一元操作符 `!` 對應邏輯非操作, 因此 `!true` 的值爲 `false`, 也可以 `(!true==false)==true`, 雖然表達方式不一樣, 不過我們一般會用簡潔的爾表達式, 就像用 x 來表示 `x==true`.
爾值可以和 && (AND) || (OR) 操作符結合, 且可能會有短路行爲: 如果運算符左邊值已經可以確定整個爾表達式的值, 那麽運算符右邊的值將不在被評估, 因此下面的表達式總是安全的:
爾值可以和 && (AND) || (OR) 操作符結合, 且可能會有短路行爲: 如果運算符左邊值已經可以確定整個爾表達式的值, 那麽運算符右邊的值將不在被評估, 因此下面的表達式總是安全的:
```Go
s != "" && s[0] == 'x'
```
其中 s[0] 應用於空字符串會導 panic 異常.
其中 s[0] 應用於空字符串會導 panic 異常.
因爲 `&&` 的優先級比 `||` (助記: `&&` 對應邏輯乘法, `||` 對應邏輯加法, 乘法比加法優先級要高), 下面形式的爾表達式是不需要加小括弧的:
因爲 `&&` 的優先級比 `||` (助記: `&&` 對應邏輯乘法, `||` 對應邏輯加法, 乘法比加法優先級要高), 下面形式的爾表達式是不需要加小括弧的:
```Go
if 'a' <= c && c <= 'z' ||
@@ -21,7 +21,7 @@ if 'a' <= c && c <= 'z' ||
}
```
爾值不會隱式轉換爲數字值0或1, 反之亦然. 必鬚使用一個顯式的if語句輔助轉換:
爾值不會隱式轉換爲數字值0或1, 反之亦然. 必鬚使用一個顯式的if語句輔助轉換:
```Go
i := 0
@@ -42,7 +42,7 @@ func btoi(b bool) int {
}
```
數字到爾型的逆轉換則非常簡單, 不過爲了保持對稱, 我們也可以包裝一個函數:
數字到爾型的逆轉換則非常簡單, 不過爲了保持對稱, 我們也可以包裝一個函數:
```Go
// itob reports whether i is non-zero.

View File

@@ -9,7 +9,7 @@
![](../images/ch3-04.png)
因爲Go語言源文件總是用UTF8編碼, 且Go的文本字符串也以UTF8編碼的方式處理, 我們可以將Unicode碼點也寫到字符串面值中.
因爲Go語言源文件總是用UTF8編碼, 且Go的文本字符串也以UTF8編碼的方式處理, 我們可以將Unicode碼點也寫到字符串面值中.
在一個雙引號包含的字符串面值中, 可以用以反斜槓\開頭的轉義序列插入任意的數據. 下面換行, 迴車和 製表符等常見的ASCII控製代碼的轉義方式:
@@ -28,9 +28,9 @@
可以通過十六進製或八進製轉義在字符串面值包含任意的字節. 一個十六進製的轉義是 \xhh, 其中兩個h表示十六進製數字(大寫或小寫都可以). 一個八進製轉義是 \ooo, 包含三個八進製的o數字(0到7), 但是不能超過\377. 每一個單一的字節表達一個特定的值. 稍後我們將看到如何將一個Unicode碼點寫到字符串面值中.
一個原生的字符串面值形式是 `...`, 使用反引號 ``` 代替雙引號. 在原生的字符串面值中, 沒有轉義操作; 全部的內容都是字面的意思, 包含退格和換行, 因此一個程序中的原生字符串面值可能跨越多行. 唯一的特殊處理是是刪除迴車以保在所有平上的值都是一樣的, 包括那些把迴車也放入文本文件的繫統.
一個原生的字符串面值形式是 `...`, 使用反引號 ``` 代替雙引號. 在原生的字符串面值中, 沒有轉義操作; 全部的內容都是字面的意思, 包含退格和換行, 因此一個程序中的原生字符串面值可能跨越多行. 唯一的特殊處理是是刪除迴車以保在所有平上的值都是一樣的, 包括那些把迴車也放入文本文件的繫統.
原生字符串面值用於編寫正則表達式會很方便, 因爲正則表達式往往會包含很多反斜槓. 原生字符串面值同時廣應用於HTML模闆, JSON面值, 命令行提示信息, 以及那些需要擴展到多行的場景.
原生字符串面值用於編寫正則表達式會很方便, 因爲正則表達式往往會包含很多反斜槓. 原生字符串面值同時廣應用於HTML模闆, JSON面值, 命令行提示信息, 以及那些需要擴展到多行的場景.
```Go
const GoUsage = `Go is a tool for managing Go source code.

View File

@@ -1,13 +1,13 @@
### 3.5.2. Unicode
在很久以前, 世界比較簡單的, 起碼計算機就隻有一個ASCII字符集: 美國信息交換標準代碼. ASCII, 更準確地是美國的ASCII, 使用 7bit 來表示 128 個字符: 包含英文字母的大小寫, 數字, 各種標點符號和設置控製符. 對於早期的計算機程序, 這些足夠了, 但是這也導了世界上很多其他地區的用戶無法直接使用自己的書寫繫統. 隨着互聯網的發展, 混合多種語言的數據變了很常見. 如何有效處理這些包含了各種語言的豐富多樣的數據呢?
在很久以前, 世界比較簡單的, 起碼計算機就隻有一個ASCII字符集: 美國信息交換標準代碼. ASCII, 更準確地是美國的ASCII, 使用 7bit 來表示 128 個字符: 包含英文字母的大小寫, 數字, 各種標點符號和設置控製符. 對於早期的計算機程序, 這些足夠了, 但是這也導了世界上很多其他地區的用戶無法直接使用自己的書寫繫統. 隨着互聯網的發展, 混合多種語言的數據變了很常見. 如何有效處理這些包含了各種語言的豐富多樣的數據呢?
答案就是使用Unicode(unicode.org), 它收集了這個世界上所有的書寫繫統, 包括重音符號和其他變音符號, 製表符和迴車符, 還有很多神祕符號, 每個符號都分配一個Unicode碼點, Unicode碼點對應Go語言中的rune類型.
第八版本的Unicode標準收集了超過120,000個字符, 涵蓋超過100種語言. 這些在計算機程序和數據中是如何體現的那? 通用的表示一個Unicode碼點的數據類型是int32, 也就是Go語言中rune對應的類型; 它的同義詞rune符文正是這個意思.
我們可以將一個符文序列表示爲一個int32序列. 這種編碼方式叫UTF-32或UCS-4, 每個Unicode碼點都使用同樣的大小32bit來表示. 這種方式比較簡單統一, 它會浪費很多存儲空間, 因爲大數據計算機可讀的文本是ASCII字符, 本來每個ASCII字符隻需要8bit或1字節就能表示. 卽使是常用的字符也遠少於65,536個, 也就是用16bit編碼方式就能表達常用字符. 但是, 還有更好的編碼方法嗎?
我們可以將一個符文序列表示爲一個int32序列. 這種編碼方式叫UTF-32或UCS-4, 每個Unicode碼點都使用同樣的大小32bit來表示. 這種方式比較簡單統一, 它會浪費很多存儲空間, 因爲大數據計算機可讀的文本是ASCII字符, 本來每個ASCII字符隻需要8bit或1字節就能表示. 卽使是常用的字符也遠少於65,536個, 也就是用16bit編碼方式就能表達常用字符. 但是, 還有更好的編碼方法嗎?

View File

@@ -1,7 +1,7 @@
### 3.5.3. UTF-8
UTF8是一个将Unicode码点编码为字节序列的变长编码. UTF8编码由Go言之父 Ken Thompson 和 Rob Pike 共同明, 在已是Unicode的标准. UTF8使用1到4个字节来表示每Unicode码点符号, ASCII部分字符使用1个字节, 常用字符部分使用2或3个字节. 每个符号编码后第一个字节的高端bit位用表示共有多少个字节. 如果第一个字节的高端bit0, 表示对应7bit的ASCII字符, 每字符一个字节, 和传统的ASCII编码兼容. 如果第一个字节的高端bit是110, 则说明需要2个字节; 后续的每高端bit都以10开头. 更大的Unicode码点也是采用似的策略理.
UTF8是一個將Unicode碼點編碼爲字節序列的變長編碼. UTF8編碼由Go言之父 Ken Thompson 和 Rob Pike 共同明, 在已是Unicode的標準. UTF8使用1到4個字節來表示每Unicode碼點符號, ASCII部分字符使用1個字節, 常用字符部分使用2或3個字節. 每個符號編碼後第一個字節的高端bit位用表示共有多少個字節. 如果第一個字節的高端bit0, 表示對應7bit的ASCII字符, 每字符一個字節, 和傳統的ASCII編碼兼容. 如果第一個字節的高端bit是110, 則説明需要2個字節; 後續的每高端bit都以10開頭. 更大的Unicode碼點也是采用似的策略理.
```
0xxxxxx runes 0-127 (ASCII)
@@ -10,11 +10,11 @@ UTF8是一个将Unicode码点编码为字节序列的变长编码. UTF8编码由
1110xxx 10xxxxxx 10xxxxxx 10xxxxxx 65536-0x10ffff (other values unused)
```
变长的编码无法直接通索引来访问第n字符, 但是UTF8得了很多外的优点. 首先UTF8编码比较紧凑, 兼容ASCII, 且可以自同步: 它可以通向前朔最多2个字节就能确定当前字符编码的开始字的位置. 它也是一个前缀编码, 所以当从左向右解码时不会有任何歧义也并不需要向前看. 有任何字符的编码是其它字符编码的子串, 或是其它编码序列的字串, 因此索一字符时只要搜索它的字节编码序列可, 不用心前的上下文会对搜索结果产生干扰. 同UTF8编码的顺序和Unicode码点的顺序一致, 因此可以直接排序UTF8编码序列. 同业也没有嵌入的NUL(0)字, 可以很好地兼容那些使用NUL作字符串尾的编程语言.
變長的編碼無法直接通索引來訪問第n字符, 但是UTF8得了很多外的優點. 首先UTF8編碼比較緊湊, 兼容ASCII, 且可以自同步: 它可以通向前朔最多2個字節就能確定當前字符編碼的開始字的位置. 它也是一個前綴編碼, 所以當從左向右解碼時不會有任何歧義也併不需要向前看. 有任何字符的編碼是其它字符編碼的子串, 或是其它編碼序列的字串, 因此索一字符時隻要蒐索它的字節編碼序列可, 不用心前的上下文會對蒐索結果産生榦擾. 同UTF8編碼的順序和Unicode碼點的順序一致, 因此可以直接排序UTF8編碼序列. 同業也沒有嵌入的NUL(0)字, 可以很好地兼容那些使用NUL作字符串尾的編程語言.
Go的源文件采用UTF8编码, 且Go理UTF8编码的文本也很色. unicode 包提供了诸多处理 rune 字符相功能的函数函数(区分字母和数组, 或者是字母的大和小写转换等), unicode/utf8 包了提供了rune 字符序列的UTF8编码和解的功能.
Go的源文件采用UTF8編碼, 且Go理UTF8編碼的文本也很色. unicode 包提供了諸多處理 rune 字符相功能的函數函數(區分字母和數組, 或者是字母的大和小寫轉換等), unicode/utf8 包了提供了rune 字符序列的UTF8編碼和解的功能.
有很多Unicode字符很直接从键盘输入, 且很多字符有着相似的结构; 有一些甚至是不可的字符. Go字符串面值中的Unicode转义字符让我们可以通Unicode码点输入特殊的字符. 有两种形式, \uhhhh 对应16bit的码点值, \Uhhhhhhhh 对应32bit的码点值, 其中h是一十六进制数字; 一般很少需要使用32bit的形式. 每一个对应码点的UTF8编码. 例如: 下面的字母串面值都表示相同的值:
有很多Unicode字符很直接從鍵盤輸入, 且很多字符有着相似的結構; 有一些甚至是不可的字符. Go字符串面值中的Unicode轉義字符讓我們可以通Unicode碼點輸入特殊的字符. 有兩種形式, \uhhhh 對應16bit的碼點值, \Uhhhhhhhh 對應32bit的碼點值, 其中h是一十六進製數字; 一般很少需要使用32bit的形式. 每一個對應碼點的UTF8編碼. 例如: 下面的字母串面值都表示相同的值:
```
"世界"
@@ -23,17 +23,17 @@ Go的源文件采用UTF8编码, 并且Go处理UTF8编码的文本也很出色. u
"\U00004e16\U0000754c"
```
上面三个转义序列第一字符串提供替代法, 但是它的值都是相同的.
上面三個轉義序列第一字符串提供替代法, 但是它的值都是相同的.
Unicode转义也可以使用在rune字符中. 下面三字符是等的:
Unicode轉義也可以使用在rune字符中. 下面三字符是等的:
```
'世' '\u4e16' '\U00004e16'
```
对于小于256码点值可以在一十六进制转义字节中, 例如 '\x41' 对应 'A' 字符, 但是对于更大的码点则必须使用 \u 或 \U 转义形式. 因此, '\xe4\xb8\x96' 不是一合法的rune字符, 虽然这三个字节对应一个有效的UTF8编码的码点.
對於小於256碼點值可以在一十六進製轉義字節中, 例如 '\x41' 對應 'A' 字符, 但是對於更大的碼點則必鬚使用 \u 或 \U 轉義形式. 因此, '\xe4\xb8\x96' 不是一合法的rune字符, 雖然這三個字節對應一個有效的UTF8編碼的碼點.
得意UTF8良的设计, 多字符串操作都不需要解. 我可以不用解直接测试一个字符串是否是另一字符串的前:
得意UTF8良的設計, 多字符串操作都不需要解. 我可以不用解直接測試一個字符串是否是另一字符串的前:
```Go
func HasPrefix(s, prefix string) bool {
@@ -41,7 +41,7 @@ func HasPrefix(s, prefix string) bool {
}
```
或者是后缀测试:
或者是後綴測試:
```Go
func HasSuffix(s, suffix string) bool {
@@ -49,7 +49,7 @@ func HasSuffix(s, suffix string) bool {
}
```
或者是包含子串测试:
或者是包含子串測試:
```Go
func Contains(s, substr string) bool {
@@ -62,9 +62,9 @@ func Contains(s, substr string) bool {
}
```
对于UTF8编码后文本的理和原始的字节处理逻辑一样. 但是对应很多其它编码则并不是这样的. (上面的函数都来自 strings 字符串理包, 然它们的实现包含了一用哈希技术优化的 Contains 实现.)
對於UTF8編碼後文本的理和原始的字節處理邏輯一樣. 但是對應很多其它編碼則併不是這樣的. (上面的函數都來自 strings 字符串理包, 然它們的實現包含了一用哈希技術優化的 Contains 實現.)
另以方面, 如果我们真的关心每Unicode字符, 我可以使用其它机制. 考前面的第一例子中的字符串, 它包混合了中西两种字符. 3.5展示了它的存表示形式. 字符串包含13个字节, 以UTF8形式编码, 但是只对应9个Unicode字符:
另以方面, 如果我們眞的關心每Unicode字符, 我可以使用其它機製. 考前面的第一例子中的字符串, 它包混合了中西兩種字符. 3.5展示了它的存表示形式. 字符串包含13個字節, 以UTF8形式編碼, 但是隻對應9個Unicode字符:
```Go
import "unicode/utf8"
@@ -74,7 +74,7 @@ fmt.Println(len(s)) // "13"
fmt.Println(utf8.RuneCountInString(s)) // "9"
```
为了处理这些真实的字符, 我需要一UTF8解器. unicode/utf8 包提供了实现, 我可以这样使用:
爲了處理這些眞實的字符, 我需要一UTF8解器. unicode/utf8 包提供了實現, 我可以這樣使用:
```Go
for i := 0; i < len(s); {
@@ -84,7 +84,7 @@ for i := 0; i < len(s); {
}
```
每一次用 DecodeRuneInString 函都返回一个 r 和 度, r 对应字符本身, 长度对应r采用UTF8编码后的字节数目. 度可以用更新第i字符在字符串中的字索引位置. 但是这种方式是笨拙的, 我需要更简洁的语法. 幸的是, Go的range循环在处理字符串的候, 会自动隐式解UTF8字符串. 下面的循环运行如3.5所示; 需要意的是对于非ASCII, 索引更新的步长超过1个字节.
每一次調用 DecodeRuneInString 函都返迴一個 r 和 度, r 對應字符本身, 長度對應r采用UTF8編碼後的字節數目. 度可以用更新第i字符在字符串中的字索引位置. 但是這種方式是笨拙的, 我需要更簡潔的語法. 幸的是, Go的range循環在處理字符串的候, 會自動隱式解UTF8字符串. 下面的循環運行如3.5所示; 需要意的是對於非ASCII, 索引更新的步長超過1個字節.
![](../images/ch3-05.png)
@@ -94,7 +94,7 @@ for i, r := range "Hello, 世界" {
}
```
可以使用一个简单的循环来统计字符串中字符的目, 像这样:
可以使用一個簡單的循環來統計字符串中字符的目, 像這樣:
```Go
n := 0
@@ -103,7 +103,7 @@ for _, _ = range s {
}
```
想其它形式的循环那样, 我可以忽略不需要的量:
想其它形式的循環那樣, 我可以忽略不需要的量:
```Go
n := 0
@@ -112,15 +112,15 @@ for range s {
}
```
或者我可以直接用 utf8.RuneCountInString(s) 函.
或者我可以直接調用 utf8.RuneCountInString(s) 函.
正如我前面提到了, 文本字符串采用UTF8编码只是一种惯例,但是对于循环的真正字符串不是一个惯例, 是正的. 如果用于循环的字符串是一普通的二进制数据, 或者是含有错误编码的UTF8数据, 将会发送什?
正如我前面提到了, 文本字符串采用UTF8編碼隻是一種慣例,但是對於循環的眞正字符串不是一個慣例, 是正的. 如果用於循環的字符串是一普通的二進製數據, 或者是含有錯誤編碼的UTF8數據, 將會發送什?
每一UTF8字符解, 不管是示地用 utf8.DecodeRuneInString 解或在 range 循环中隐式地解, 如果遇到一个错误的输入字, 生成一特别的Unicode字符 '\uFFFD', 在印刷中这个符号通常是一黑色六角或石形, 里面包含一白色的问号(?). 程序遇到这样的一字符, 通常是一个信号, 说明输入并不是一完美没有错误的的UTF8编码字符串.
每一UTF8字符解, 不管是示地調用 utf8.DecodeRuneInString 解或在 range 循環中隱式地解, 如果遇到一個錯誤的輸入字, 生成一特别的Unicode字符 '\uFFFD', 在印刷中這個符號通常是一黑色六角或石形, 里面包含一白色的問號(?). 程序遇到這樣的一字符, 通常是一個信號, 説明輸入併不是一完美沒有錯誤的的UTF8編碼字符串.
UTF8作为交换格式是非常方便的, 但是在程序部采用rune型可能更方便, 因rune大小一致, 支持数组索引和方便切割.
UTF8作爲交換格式是非常方便的, 但是在程序部采用rune型可能更方便, 因rune大小一致, 支持數組索引和方便切割.
string 接受到 []rune 的转换, 可以将一个UTF8编码的字符串解码为Unicode字符序列:
string 接受到 []rune 的轉換, 可以將一個UTF8編碼的字符串解碼爲Unicode字符序列:
```Go
// "program" in Japanese katakana
@@ -130,22 +130,22 @@ r := []rune(s)
fmt.Printf("%x\n", r) // "[30d7 30ed 30b0 30e9 30e0]"
```
(在第一Printf中的 `% x` 参数用于在每十六进制数字前插入一空格.)
(在第一Printf中的 `% x` 參數用於在每十六進製數字前插入一空格.)
如果是将一个 []rune 型的Unicode字符切片或数组转为string, 则对它们进行UTF8编码:
如果是將一個 []rune 型的Unicode字符切片或數組轉爲string, 則對它們進行UTF8編碼:
```Go
fmt.Println(string(r)) // "プログラム"
```
将一个整数转型为字符串意思是生成整数作为Unicode码点的UTF8编码的字符串:
將一個整數轉型爲字符串意思是生成整數作爲Unicode碼點的UTF8編碼的字符串:
```Go
fmt.Println(string(65)) // "A", not "65"
fmt.Println(string(0x4eac)) // "京"
```
如果对应码点的字符是效的, 用'\uFFFD'效字符作为替换:
如果對應碼點的字符是效的, 用'\uFFFD'效字符作爲替換:
```Go
fmt.Println(string(1234567)) // "(?)"

View File

@@ -17,7 +17,7 @@ FormatInt和FormatUint可以用不同的進製來格式化數字:
fmt.Println(strconv.FormatInt(int64(x), 2)) // "1111011"
```
fmt.Printf 函數的 %b, %d, %u, 和 %x 等參數提供功能往往比strconv 包的 Format 函數方便很多, 特是在需要包含附加信息的時候:
fmt.Printf 函數的 %b, %d, %u, 和 %x 等參數提供功能往往比strconv 包的 Format 函數方便很多, 特是在需要包含附加信息的時候:
```Go
s := fmt.Sprintf("x=%b", x) // "x=1111011"
@@ -32,7 +32,7 @@ y, err := strconv.ParseInt("123", 10, 64) // base 10, up to 64 bits
ParseInt 函數的第三個參數是用於指定整型數的大小; 例如16表示int16, 0則表示int. 在任何情況下, 返迴的結果 y 總是 int64 類型, 你可以通過強製類型轉換將它轉爲更小的整數類型.
有時候也會使用 fmt.Scanf 來解析輸入的字符串和數字, 特是當字符串和數字混合在一行的時候, 它可以靈活處理不完整或不規則的輸入.
有時候也會使用 fmt.Scanf 來解析輸入的字符串和數字, 特是當字符串和數字混合在一行的時候, 它可以靈活處理不完整或不規則的輸入.

View File

@@ -1,6 +1,6 @@
## 3.5. 字符串
一個字符串是一個不可改變的字節序列. 字符串可以包含任意的數據, 包括字節值0, 但是通常包含人類可讀的文本. 文本字符串通常被解釋爲用UTF8編碼的Unicode碼點(rune)序列, 我們稍後會詳細討論這個問題.
一個字符串是一個不可改變的字節序列. 字符串可以包含任意的數據, 包括字節值0, 但是通常包含人類可讀的文本. 文本字符串通常被解釋爲用UTF8編碼的Unicode碼點(rune)序列, 我們稍後會詳細討論這個問題.
內置的 len 函數可以返迴一個字符串的字節數目(不是rune字符數目), 索引操作 s[i] 返迴第i個字節的字節值, i 必鬚滿足 0 ≤ i< len(s) 條件約束.
@@ -12,23 +12,23 @@ fmt.Println(s[0], s[7]) // "104 119" ('h' and 'w')
Attempting to access a byte outside this range results in a panic:
如果視圖訪問超齣字符串圍的字節將會導panic異常:
如果視圖訪問超齣字符串圍的字節將會導panic異常:
```Go
c := s[len(s)] // panic: index out of range
```
第i個字節不一定是字符串的第i個字符, 因此對於非ASCII字符的UTF8編碼會要兩個或多個字節. 我們簡單下字符的工作方式.
第i個字節不一定是字符串的第i個字符, 因此對於非ASCII字符的UTF8編碼會要兩個或多個字節. 我們簡單下字符的工作方式.
子字符串操作s[i:j]基於原始的s字符串的第i個字節開始到第j個字節(不包含j本身)生成一個新字符串. 生成的子字符串將包含 j-i 個字節.
子字符串操作s[i:j]基於原始的s字符串的第i個字節開始到第j個字節(不包含j本身)生成一個新字符串. 生成的子字符串將包含 j-i 個字節.
```Go
fmt.Println(s[0:5]) // "hello"
```
同樣, 如果索引超齣字符串圍或者j小於i的話將導panic異常.
同樣, 如果索引超齣字符串圍或者j小於i的話將導panic異常.
不管i還是j都可能被忽略, 當它們被忽略時將用0作爲開始位置, len(s) 作爲接受的位置.
不管i還是j都可能被忽略, 當它們被忽略時將用0作爲開始位置, len(s) 作爲接受的位置.
```Go
fmt.Println(s[:5]) // "hello"
@@ -53,20 +53,20 @@ t := s
s += ", right foot"
```
不會導原始的字符串值被改變, 但是 s 將因爲 += 語句持有一個新的字符串值, 但是 t 依然是包含原先的字符串值.
不會導原始的字符串值被改變, 但是 s 將因爲 += 語句持有一個新的字符串值, 但是 t 依然是包含原先的字符串值.
```Go
fmt.Println(s) // "left foot, right foot"
fmt.Println(t) // "left foot"
```
因爲字符串是不可脩改的, 因此試脩改字符串內部數據的操作是被禁止的:
因爲字符串是不可脩改的, 因此試脩改字符串內部數據的操作是被禁止的:
```Go
s[0] = 'L' // compile error: cannot assign to s[0]
```
不變性意味如果兩個字符串共享相同的底層數據是安全的, 這使得製任何長度的字符串代價是低廉的. 同樣, 一個字符串 s 和對應的子字符串 s[7:] 也可以安全地共享相同的內存, 因此字符串切片操作代價也是低廉的. 在這兩種情況下都沒有必要分配新的內存. 圖3.4 演示了一個字符串和兩個字串共享相同的底層數據.
不變性意味如果兩個字符串共享相同的底層數據是安全的, 這使得製任何長度的字符串代價是低廉的. 同樣, 一個字符串 s 和對應的子字符串 s[7:] 也可以安全地共享相同的內存, 因此字符串切片操作代價也是低廉的. 在這兩種情況下都沒有必要分配新的內存. 圖3.4 演示了一個字符串和兩個字串共享相同的底層數據.
{% include "./ch3-05-1.md" %}

View File

@@ -1,5 +1,5 @@
# 第3章 基礎數據類型
雖然從底層而言,所有的數據都是比特,但計算機操作的是固定位數的數,如整數、浮點數、比特組、內存地址。將這些數,進一步組織在一起,可表達更多的對象,如數據包、像素點、詩歌,甚至任何對象.Go提供了豐富的數據組織形式,這依賴於Go內置的數據類型。這些內置的數據類型兼顧了硬件的特性和表達雜數據結構的便捷性。
雖然從底層而言,所有的數據都是比特,但計算機操作的是固定位數的數,如整數、浮點數、比特組、內存地址。將這些數,進一步組織在一起,可表達更多的對象,如數據包、像素點、詩歌,甚至任何對象.Go提供了豐富的數據組織形式,這依賴於Go內置的數據類型。這些內置的數據類型兼顧了硬件的特性和表達雜數據結構的便捷性。
Go將數據類型分爲四類基礎類型、合類型、引用類型和接口類型。本章介紹基礎類型,包括:數字,字符串和爾型。合數據類型——數組§4.1和結構體§4.2)——通過組合簡單類型,表達更加雜的數據結構。引用類型包括指§2.3.2、切片§4.2)字典§4.3、函數§5、通道§8.雖然種類很多,但它們都是對程序中一個變量或狀態的間接引用。這意味着對任一引用的脩改都會影響所有該引用的拷貝。我們將在第7章介紹接口類型。
Go將數據類型分爲四類基礎類型、合類型、引用類型和接口類型。本章介紹基礎類型,包括:數字,字符串和爾型。合數據類型——數組§4.1和結構體§4.2)——通過組合簡單類型,表達更加雜的數據結構。引用類型包括指§2.3.2、切片§4.2)字典§4.3、函數§5、通道§8.雖然種類很多,但它們都是對程序中一個變量或狀態的間接引用。這意味着對任一引用的脩改都會影響所有該引用的拷貝。我們將在第7章介紹接口類型。