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
+1 -1
View File
@@ -1,3 +1,3 @@
## 3.3. 復數
## 3.3. 複數
TODO
+7 -7
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.
+3 -3
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.
+2 -2
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編碼方式就能表達常用字符. 但是, 還有更好的編碼方法嗎?
+25 -25
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位用于表示总共有多少个字节. 如果第一个字节的高端bit为0, 则表示对应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位用於表示總共有多少個字節. 如果第一個字節的高端bit爲0, 則表示對應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)) // "(?)"
+2 -2
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 來解析輸入的字符串和數字, 特别是當字符串和數字混合在一行的時候, 它可以靈活處理不完整或不規則的輸入.
+9 -9
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" %}
+2 -2
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章介紹接口類型。