mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-18 19:54:21 +08:00
rebuild
This commit is contained in:
209
ch3/ch3-01.html
209
ch3/ch3-01.html
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="3.1" data-chapter-title="整型" data-filepath="ch3/ch3-01.md" data-basepath=".." data-revision="Wed Dec 16 2015 10:54:29 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="3.1" data-chapter-title="整型" data-filepath="ch3/ch3-01.md" data-basepath=".." data-revision="Mon Dec 21 2015 12:51:02 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
<b>0.5.</b>
|
||||
|
||||
緻謝
|
||||
致謝
|
||||
</a>
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
|
||||
<b>1.3.</b>
|
||||
|
||||
査找重復的行
|
||||
査找重複的行
|
||||
</a>
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
|
||||
<b>1.4.</b>
|
||||
|
||||
GIF動畫
|
||||
GIF動畵
|
||||
</a>
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
<b>1.6.</b>
|
||||
|
||||
併髮穫取多個URL
|
||||
併發穫取多個URL
|
||||
</a>
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
|
||||
<b>3.3.</b>
|
||||
|
||||
復數
|
||||
複數
|
||||
</a>
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@
|
||||
|
||||
<b>3.4.</b>
|
||||
|
||||
佈爾型
|
||||
布爾型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@
|
||||
|
||||
<b>4.</b>
|
||||
|
||||
復閤數據類型
|
||||
複合數據類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@
|
||||
|
||||
<b>6.2.</b>
|
||||
|
||||
基於指鍼對象的方法
|
||||
基於指針對象的方法
|
||||
</a>
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
|
||||
<b>6.4.</b>
|
||||
|
||||
方法值和方法錶達式
|
||||
方法值和方法表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -953,7 +953,7 @@
|
||||
|
||||
<b>7.1.</b>
|
||||
|
||||
接口是閤約
|
||||
接口是合約
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1073,7 +1073,7 @@
|
||||
|
||||
<b>7.9.</b>
|
||||
|
||||
示例: 錶達式求值
|
||||
示例: 表達式求值
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1103,7 +1103,7 @@
|
||||
|
||||
<b>7.11.</b>
|
||||
|
||||
基於類型斷言識彆錯誤類型
|
||||
基於類型斷言識别錯誤類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1214,7 +1214,7 @@
|
||||
|
||||
<b>8.2.</b>
|
||||
|
||||
示例: 併髮的Clock服務
|
||||
示例: 併發的Clock服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1229,7 +1229,7 @@
|
||||
|
||||
<b>8.3.</b>
|
||||
|
||||
示例: 併髮的Echo服務
|
||||
示例: 併發的Echo服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1274,7 +1274,7 @@
|
||||
|
||||
<b>8.6.</b>
|
||||
|
||||
示例: 併髮的Web爬蟲
|
||||
示例: 併發的Web爬蟲
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1289,7 +1289,7 @@
|
||||
|
||||
<b>8.7.</b>
|
||||
|
||||
基於select的多路復用
|
||||
基於select的多路複用
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1304,7 +1304,7 @@
|
||||
|
||||
<b>8.8.</b>
|
||||
|
||||
示例: 併髮的字典遍歷
|
||||
示例: 併發的字典遍歷
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1319,7 +1319,7 @@
|
||||
|
||||
<b>8.9.</b>
|
||||
|
||||
併髮的退齣
|
||||
併發的退齣
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1354,7 +1354,7 @@
|
||||
|
||||
<b>9.</b>
|
||||
|
||||
基於共享變量的併髮
|
||||
基於共享變量的併發
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1415,7 +1415,7 @@
|
||||
|
||||
<b>9.4.</b>
|
||||
|
||||
內存衕步
|
||||
內存同步
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1460,7 +1460,7 @@
|
||||
|
||||
<b>9.7.</b>
|
||||
|
||||
示例: 併髮的非阻塞緩存
|
||||
示例: 併發的非阻塞緩存
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1475,7 +1475,7 @@
|
||||
|
||||
<b>9.8.</b>
|
||||
|
||||
Goroutines和綫程
|
||||
Goroutines和線程
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1748,7 +1748,7 @@
|
||||
|
||||
<b>12.1.</b>
|
||||
|
||||
為何需要反射?
|
||||
爲何需要反射?
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1793,7 +1793,7 @@
|
||||
|
||||
<b>12.4.</b>
|
||||
|
||||
示例: 編碼S錶達式
|
||||
示例: 編碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1823,7 +1823,7 @@
|
||||
|
||||
<b>12.6.</b>
|
||||
|
||||
示例: 解碼S錶達式
|
||||
示例: 解碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1975,50 +1975,14 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="14" data-path="exercise/ex.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.</b>
|
||||
|
||||
習題解答
|
||||
</a>
|
||||
|
||||
|
||||
<ul class="articles">
|
||||
|
||||
|
||||
<li class="chapter " data-level="14.1" data-path="exercise/ex-ch1.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex-ch1.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.1.</b>
|
||||
|
||||
第一章 入門
|
||||
</a>
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="15" data-path="errata.html">
|
||||
<li class="chapter " data-level="14" data-path="errata.html">
|
||||
|
||||
|
||||
<a href="../errata.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>15.</b>
|
||||
<b>14.</b>
|
||||
|
||||
勘誤
|
||||
</a>
|
||||
@@ -2060,7 +2024,122 @@
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h2 id="31-整型">3.1. 整型</h2>
|
||||
<p>TODO</p>
|
||||
<p>Go語言的數值類型包括幾種不同大小的整形數, 浮點數, 和複數. 每種數值類型都決定了對應的大小范圍和是否有正負符號. 讓我們先從整形數類型開始介紹.</p>
|
||||
<p>Go同時提供了有符號和無符號的整數運算. 這里有四種int8, int16, int32 和 int64截然不同大小的有符號整形數類型, 分别對應 8, 16, 32, 64 bit 大小的有符號整形數, 與此對應的是 uint8, uint16, uint32, 和 uint64 四種無符號整形數類型.</p>
|
||||
<p>這里還有兩種對應特定平颱最天然或最有效率的大小有符號和無符號整數int和uint; 其中int是應用最廣泛的數值類型. 這兩種類型都有同樣的大小, 32 或 64 bit, 但是我們不能對此做任何的假設; 因爲不同的編譯器在相同的硬件平颱上可能産生不同的大小.</p>
|
||||
<p>字符rune類型是和int32等價的類型, 通常用於表示一個Unicode碼點. 這兩個名稱可以互換使用. 同樣byte也是uint8類型的等價類型, byte類型用於強調數值是一個原始的數據而不是一個小的整數.</p>
|
||||
<p>最好, 還有一個無符號的整數類型 uintptr, 沒有指定具體的bit大小但是足以容納指針. uintptr 類型隻有在底層編程是纔需要, 特别是Go語言和C函數庫或操作繫統相交互的地方. 我們將在第十三章的 unsafe 包相關部分看到類似的例子.</p>
|
||||
<p>不管它們的大小, int, uint, 和 uintptr 是不同類型大小的兄弟類型. 其中 int 和 int32 也是不同的類型, 卽使int的大小也是32bit, 在需要將int當作int32類型的地方需要一個顯式的類型轉換, 反之亦然.</p>
|
||||
<p>有符號數采用2的補碼形式表示, 也就是最高位用作符號位, 一個nbit的有符號數的值域是 <code>-2^(n-1)</code> 到 <code>(2^(n-1)) - 1</code>. 無符號整數的所有bit位都用於表示非負數, 值域是 0 到 <code>(2^n) - 1</code>. 例如, int8 的值域是 -128 到 127, 而 uint8 的值域是 0 到 255.</p>
|
||||
<p>下面是Go中關於算術, 邏輯和比較的二元運算符按照先級遞減的順序的列表:</p>
|
||||
<pre><code>* / % << >> & &^
|
||||
+ - | ^
|
||||
== != < <= > >=
|
||||
&&
|
||||
||
|
||||
</code></pre><p>二元運算符有五種優先級. 在同一優先級, 使用左優先結合律, 使用括號可以明確優先順序, 括號也可以用於提陞優先級, 例如 <code>mask & (1 << 28)</code>.</p>
|
||||
<p>對於上表中前兩行的運算符, 例如 + 有一個相應的賦值結合運算符 +=, 可以用於簡化賦值語句.</p>
|
||||
<p>整數的算術運算符 +, -, *, 和 / 可以適用與整數, 浮點數和複數, 但是取模運算符 % 僅用於整數. 不同編程語言間, % 取模運算的行爲併不相同. 在Go語言中, % 取模運算符的符號和被取模數的符號總是一致的, 因此 <code>-5%3</code> 和 <code>-5%-3</code> 結果都是 -2.除法運算符 <code>/</code> 的行爲依賴於操作數是否爲整數, 因此 <code>5.0/4.0</code> 的結果是 1.25, 但是 5/4 的結果是 1, 因此整數除法會向着0方向截斷餘數.</p>
|
||||
<p>如果一個算術運算的結果, 不管是有符號或者是無符號的, 如果需要更多的bit位纔能表示, 就説明是溢齣了. 超齣的高位的bit位部分將被丟棄. 如果原始的數值是有符號類型, 那麽最終結果可能是負的, 如果最左邊的bit爲是1的話, 例如int8的例子:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> u <span class="hljs-typename">uint8</span> = <span class="hljs-number">255</span>
|
||||
fmt.Println(u, u+<span class="hljs-number">1</span>, u*u) <span class="hljs-comment">// "255 0 1"</span>
|
||||
|
||||
<span class="hljs-keyword">var</span> i <span class="hljs-typename">int8</span> = <span class="hljs-number">127</span>
|
||||
fmt.Println(i, i+<span class="hljs-number">1</span>, i*i) <span class="hljs-comment">// "127 -128 1"</span>
|
||||
</code></pre>
|
||||
<p>兩個相同的整數類型可以使用下面的二元比較運算符進行比較; 比較表達式的結果是布爾類型.</p>
|
||||
<pre><code>== equal to
|
||||
!= not equal to
|
||||
< less than
|
||||
<= less than or equal to
|
||||
> greater than
|
||||
>= greater than or equal to
|
||||
</code></pre><p>事實上, 布爾型, 數字類型 和 字符串 等基本類型都是可比較的, 也就是説兩個相同類型的值可以用 == 和 != 進行比較. 此外, 整數, 浮點數和字符串可以根據比較結果排序. 許多其他類型的值是不可比較, 因此也就是不可排序的. 對於我們遇到的每種類型, 我們需要保證規則是類似的.</p>
|
||||
<p>這里是一元的加法和減法運算符:</p>
|
||||
<pre><code>+ 一元加法 (無效果)
|
||||
- 負數
|
||||
</code></pre><p>對於整數, +x 是 0+x 的簡寫, -x 是 0-x 的簡寫; 對於浮點數和複數, +x 就是 x, -x 則是 x 的負數.</p>
|
||||
<p>Go語言還提供了以下的bit位操作運算符, 前面4個操作運算符併不區分是有符號還是無符號數:</p>
|
||||
<pre><code>& 位運算 AND
|
||||
| 位運算 OR
|
||||
^ 位運算 XOR
|
||||
&^ 位清空 (AND NOT)
|
||||
<< 左移
|
||||
>> 右移
|
||||
</code></pre><p>位操作運算符 <code>^</code> 作爲二元運算符時是按位異或(XOR), 當用作一元運算符時表示按位取反; 也就是説, 它返迴一個每個bit位都取反的數. 位操作運算符 <code>&^</code> 用於按位置零(AND NOT): 表達式 <code>z = x &^ y</code> 結果z的bit位1, 如果對應y中bit位爲1, 否則對應的bit位等於x相應的bit位的值.</p>
|
||||
<p>下面的代碼演示了如何使用位操作解釋uint8類型值的8個獨立的bit位. 它使用了 Printf 函數的 %b 參數打印二進製格式的數字; 其中 %08b 中08表示打印至少8個數字, 不足的前綴用0填充.</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> x <span class="hljs-typename">uint8</span> = <span class="hljs-number">1</span><<<span class="hljs-number">1</span> | <span class="hljs-number">1</span><<<span class="hljs-number">5</span>
|
||||
<span class="hljs-keyword">var</span> y <span class="hljs-typename">uint8</span> = <span class="hljs-number">1</span><<<span class="hljs-number">1</span> | <span class="hljs-number">1</span><<<span class="hljs-number">2</span>
|
||||
|
||||
fmt.Printf(<span class="hljs-string">"%08b\n"</span>, x) <span class="hljs-comment">// "00100010", the set {1, 5}</span>
|
||||
fmt.Printf(<span class="hljs-string">"%08b\n"</span>, y) <span class="hljs-comment">// "00000110", the set {1, 2}</span>
|
||||
|
||||
fmt.Printf(<span class="hljs-string">"%08b\n"</span>, x&y) <span class="hljs-comment">// "00000010", the intersection {1}</span>
|
||||
fmt.Printf(<span class="hljs-string">"%08b\n"</span>, x|y) <span class="hljs-comment">// "00100110", the union {1, 2, 5}</span>
|
||||
fmt.Printf(<span class="hljs-string">"%08b\n"</span>, x^y) <span class="hljs-comment">// "00100100", the symmetric difference {2, 5}</span>
|
||||
fmt.Printf(<span class="hljs-string">"%08b\n"</span>, x&^y) <span class="hljs-comment">// "00100000", the difference {5}</span>
|
||||
|
||||
<span class="hljs-keyword">for</span> i := <span class="hljs-typename">uint</span>(<span class="hljs-number">0</span>); i < <span class="hljs-number">8</span>; i++ {
|
||||
<span class="hljs-keyword">if</span> x&(<span class="hljs-number">1</span><<i) != <span class="hljs-number">0</span> { <span class="hljs-comment">// membership test</span>
|
||||
fmt.Println(i) <span class="hljs-comment">// "1", "5"</span>
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf(<span class="hljs-string">"%08b\n"</span>, x<<<span class="hljs-number">1</span>) <span class="hljs-comment">// "01000100", the set {2, 6}</span>
|
||||
fmt.Printf(<span class="hljs-string">"%08b\n"</span>, x>><span class="hljs-number">1</span>) <span class="hljs-comment">// "00010001", the set {0, 4}</span>
|
||||
</code></pre>
|
||||
<p>(6.5節給齣了一個可以遠大於一個字節的整數集的實現.)</p>
|
||||
<p>在 x<<n 和="" x="">>n 移位運算中, 決定了移位操作bit數部分必鬚是無符號數; 被操作的 x 數可以是有符號或無符號數. 算術上, 一個 x<<n 左移運算等價於乘以="" 2^n,="" 一個="" x="">>n 右移運算等價於除以 2^n.</n></n></p>
|
||||
<p>左移運算用零填充右邊空缺的bit位, 無符號數的右移運算也是用0填充左邊空缺的bit位, 但是有符號數的右移運算會用符號位的值填充左邊空缺的bit位. 因爲這個原因, 最好用無符號運算, 這樣你可以將整數完全當作一個bit位模式處理.</p>
|
||||
<p>盡管Go提供了無符號數和運算, 卽使數值本身不可能齣現負數我們還是傾向於使用有符號的int類型, 就是數組的長度那樣, 雖然使用 uint 似乎是一個更合理的選擇. 事實上, 內置的 len 函數返迴一個有符號的int, 我們可以像下面這個逆序循環那樣處理.</p>
|
||||
<pre><code class="lang-Go">medals := []<span class="hljs-typename">string</span>{<span class="hljs-string">"gold"</span>, <span class="hljs-string">"silver"</span>, <span class="hljs-string">"bronze"</span>}
|
||||
<span class="hljs-keyword">for</span> i := <span class="hljs-built_in">len</span>(medals) - <span class="hljs-number">1</span>; i >= <span class="hljs-number">0</span>; i-- {
|
||||
fmt.Println(medals[i]) <span class="hljs-comment">// "bronze", "silver", "gold"</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>另一個選擇將是災難性的. 如果 len 返迴一個無符號數, 那麽 i 也將是無符號的 uint, 然後條件 i >= 0 則永遠爲眞. 在三次迭代之後, 也就是 i == 0 時, i-- 語句將不會産生 -1, 而是變成一個uint的最大值(可能是 2^64 - 1), 然後 medals[i] 表達式將發生運行時 panic 異常(§5.9), 也就是試圖訪問一個切片范圍以外的元素.</p>
|
||||
<p>齣於這個原因, 無符號數往往隻有在位運算或其它特殊的運算常見纔會使用, 就像 bit 集合, 分形二進製文件格式, 或者是哈希和加密操作等. 它們通常併不用於僅僅是表達非負數量的場合.</p>
|
||||
<p>一般來説, 需要一個顯式的轉換將一個值從一種類型轉化位另一種類型, 併且算術和邏輯運算的二元操作中必鬚是相同的類型. 雖然這偶爾會導致很長的表達式, 但是它消除了所有的類型相關的問題, 也使得程序容易理解.</p>
|
||||
<p>從其他類似場景下, 考慮下面這個代碼:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> apples <span class="hljs-typename">int32</span> = <span class="hljs-number">1</span>
|
||||
<span class="hljs-keyword">var</span> oranges <span class="hljs-typename">int16</span> = <span class="hljs-number">2</span>
|
||||
<span class="hljs-keyword">var</span> compote <span class="hljs-typename">int</span> = apples + oranges <span class="hljs-comment">// compile error</span>
|
||||
</code></pre>
|
||||
<p>當嚐試編譯這三個語句時, 將産生一個錯誤信息:</p>
|
||||
<pre><code>invalid operation: apples + oranges (mismatched types int32 and int16)
|
||||
</code></pre><p>這種類型不匹配的問題可以有幾種不同的方法脩複, 最常見方法是將它們都顯式轉型位一個常見類型:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> compote = <span class="hljs-typename">int</span>(apples) + <span class="hljs-typename">int</span>(oranges)
|
||||
</code></pre>
|
||||
<p>如2.5節所述, 對於每種類型T, 類型轉換操作T(x)將x轉換位T類型, 如果轉換允許的話. 許多 整形數之間的相互轉換併不會改變數值; 它們隻是告訴編譯器如何解釋這個值. 但是對於將一個大尺寸的整數類型轉位一個小尺寸的整數類型, 或者是將一個浮點數轉位整數, 可能會改變數值或丟失精度:</p>
|
||||
<pre><code class="lang-Go">f := <span class="hljs-number">3.141</span> <span class="hljs-comment">// a float64</span>
|
||||
i := <span class="hljs-typename">int</span>(f)
|
||||
fmt.Println(f, i) <span class="hljs-comment">// "3.141 3"</span>
|
||||
f = <span class="hljs-number">1.99</span>
|
||||
fmt.Println(<span class="hljs-typename">int</span>(f)) <span class="hljs-comment">// "1"</span>
|
||||
</code></pre>
|
||||
<p>浮點數到整數的轉換將丟失任何小數部分, 向數軸零方向截斷. 你應該避免操作目標類型表示范圍的數值類型轉換, 因爲截斷的行爲依賴於具體的實現:</p>
|
||||
<pre><code class="lang-Go">f := <span class="hljs-number">1e100</span> <span class="hljs-comment">// a float64</span>
|
||||
i := <span class="hljs-typename">int</span>(f) <span class="hljs-comment">// 結果依賴於具體實現</span>
|
||||
</code></pre>
|
||||
<p>任何大小的整數字面值都可以用以0開始的八進製格式書寫, 例如 0666, 或用以0x或0X開頭的十六進製格式書寫, 例如 0xdeadbeef. 十六進製數字可以用大寫或小寫字母. 如今八進製數據通常用於POSIX操作繫統上的文件訪問權限標誌, 十六進製數字則更強調數字值的bit位模式.</p>
|
||||
<p>當使用 fmt 包打印一個數值時, 我們可以用 %d, %o, 或 %x 控製輸齣的進製格式, 就像下面的例子:</p>
|
||||
<pre><code class="lang-Go">o := <span class="hljs-number">0666</span>
|
||||
fmt.Printf(<span class="hljs-string">"%d %[1]o %#[1]o\n"</span>, o) <span class="hljs-comment">// "438 666 0666"</span>
|
||||
x := <span class="hljs-typename">int64</span>(<span class="hljs-number">0xdeadbeef</span>)
|
||||
fmt.Printf(<span class="hljs-string">"%d %[1]x %#[1]x %#[1]X\n"</span>, x)
|
||||
<span class="hljs-comment">// Output:</span>
|
||||
<span class="hljs-comment">// 3735928559 deadbeef 0xdeadbeef 0XDEADBEEF</span>
|
||||
</code></pre>
|
||||
<p>請註意 fmt 的兩個使用技巧. 通常 Printf 格式化字符串包含多個 % 參數時將對應相同數量的額外操作數, 但是 % 之後的 <code>[1]</code> 副詞告訴Printf函數再次使用第一個操作數. 第二, % 後的 <code>#</code> 副詞告訴 Printf 在用 %o, %x 或 %X 輸齣時生成 0, 0x 或 0X前綴.</p>
|
||||
<p>字符面值通過一對單引號直接包含對應字符. 最簡單的例子是 ASCII 中類似 'a' 字符面值, 但是我們可以通過轉義的數值來表示任意的Unicode碼點對應的字符, 馬上將會看到例子.</p>
|
||||
<p>字符使用 <code>%c</code> 參數打印, 或者是 <code>%q</code> 參數打印帶單引號的字符:</p>
|
||||
<pre><code class="lang-Go">ascii := <span class="hljs-string">'a'</span>
|
||||
unicode := <span class="hljs-string">'國'</span>
|
||||
newline := <span class="hljs-string">'\n'</span>
|
||||
fmt.Printf(<span class="hljs-string">"%d %[1]c %[1]q\n"</span>, ascii) <span class="hljs-comment">// "97 a 'a'"</span>
|
||||
fmt.Printf(<span class="hljs-string">"%d %[1]c %[1]q\n"</span>, unicode) <span class="hljs-comment">// "22269 國 '國'"</span>
|
||||
fmt.Printf(<span class="hljs-string">"%d %[1]q\n"</span>, newline) <span class="hljs-comment">// "10 '\n'"</span>
|
||||
</code></pre>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
211
ch3/ch3-02.html
211
ch3/ch3-02.html
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="3.2" data-chapter-title="浮點數" data-filepath="ch3/ch3-02.md" data-basepath=".." data-revision="Wed Dec 16 2015 10:54:29 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="3.2" data-chapter-title="浮點數" data-filepath="ch3/ch3-02.md" data-basepath=".." data-revision="Mon Dec 21 2015 12:51:02 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
<b>0.5.</b>
|
||||
|
||||
緻謝
|
||||
致謝
|
||||
</a>
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
|
||||
<b>1.3.</b>
|
||||
|
||||
査找重復的行
|
||||
査找重複的行
|
||||
</a>
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
|
||||
<b>1.4.</b>
|
||||
|
||||
GIF動畫
|
||||
GIF動畵
|
||||
</a>
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
<b>1.6.</b>
|
||||
|
||||
併髮穫取多個URL
|
||||
併發穫取多個URL
|
||||
</a>
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
|
||||
<b>3.3.</b>
|
||||
|
||||
復數
|
||||
複數
|
||||
</a>
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@
|
||||
|
||||
<b>3.4.</b>
|
||||
|
||||
佈爾型
|
||||
布爾型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@
|
||||
|
||||
<b>4.</b>
|
||||
|
||||
復閤數據類型
|
||||
複合數據類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@
|
||||
|
||||
<b>6.2.</b>
|
||||
|
||||
基於指鍼對象的方法
|
||||
基於指針對象的方法
|
||||
</a>
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
|
||||
<b>6.4.</b>
|
||||
|
||||
方法值和方法錶達式
|
||||
方法值和方法表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -953,7 +953,7 @@
|
||||
|
||||
<b>7.1.</b>
|
||||
|
||||
接口是閤約
|
||||
接口是合約
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1073,7 +1073,7 @@
|
||||
|
||||
<b>7.9.</b>
|
||||
|
||||
示例: 錶達式求值
|
||||
示例: 表達式求值
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1103,7 +1103,7 @@
|
||||
|
||||
<b>7.11.</b>
|
||||
|
||||
基於類型斷言識彆錯誤類型
|
||||
基於類型斷言識别錯誤類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1214,7 +1214,7 @@
|
||||
|
||||
<b>8.2.</b>
|
||||
|
||||
示例: 併髮的Clock服務
|
||||
示例: 併發的Clock服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1229,7 +1229,7 @@
|
||||
|
||||
<b>8.3.</b>
|
||||
|
||||
示例: 併髮的Echo服務
|
||||
示例: 併發的Echo服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1274,7 +1274,7 @@
|
||||
|
||||
<b>8.6.</b>
|
||||
|
||||
示例: 併髮的Web爬蟲
|
||||
示例: 併發的Web爬蟲
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1289,7 +1289,7 @@
|
||||
|
||||
<b>8.7.</b>
|
||||
|
||||
基於select的多路復用
|
||||
基於select的多路複用
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1304,7 +1304,7 @@
|
||||
|
||||
<b>8.8.</b>
|
||||
|
||||
示例: 併髮的字典遍歷
|
||||
示例: 併發的字典遍歷
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1319,7 +1319,7 @@
|
||||
|
||||
<b>8.9.</b>
|
||||
|
||||
併髮的退齣
|
||||
併發的退齣
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1354,7 +1354,7 @@
|
||||
|
||||
<b>9.</b>
|
||||
|
||||
基於共享變量的併髮
|
||||
基於共享變量的併發
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1415,7 +1415,7 @@
|
||||
|
||||
<b>9.4.</b>
|
||||
|
||||
內存衕步
|
||||
內存同步
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1460,7 +1460,7 @@
|
||||
|
||||
<b>9.7.</b>
|
||||
|
||||
示例: 併髮的非阻塞緩存
|
||||
示例: 併發的非阻塞緩存
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1475,7 +1475,7 @@
|
||||
|
||||
<b>9.8.</b>
|
||||
|
||||
Goroutines和綫程
|
||||
Goroutines和線程
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1748,7 +1748,7 @@
|
||||
|
||||
<b>12.1.</b>
|
||||
|
||||
為何需要反射?
|
||||
爲何需要反射?
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1793,7 +1793,7 @@
|
||||
|
||||
<b>12.4.</b>
|
||||
|
||||
示例: 編碼S錶達式
|
||||
示例: 編碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1823,7 +1823,7 @@
|
||||
|
||||
<b>12.6.</b>
|
||||
|
||||
示例: 解碼S錶達式
|
||||
示例: 解碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1975,50 +1975,14 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="14" data-path="exercise/ex.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.</b>
|
||||
|
||||
習題解答
|
||||
</a>
|
||||
|
||||
|
||||
<ul class="articles">
|
||||
|
||||
|
||||
<li class="chapter " data-level="14.1" data-path="exercise/ex-ch1.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex-ch1.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.1.</b>
|
||||
|
||||
第一章 入門
|
||||
</a>
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="15" data-path="errata.html">
|
||||
<li class="chapter " data-level="14" data-path="errata.html">
|
||||
|
||||
|
||||
<a href="../errata.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>15.</b>
|
||||
<b>14.</b>
|
||||
|
||||
勘誤
|
||||
</a>
|
||||
@@ -2060,7 +2024,122 @@
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h2 id="32-浮點數">3.2. 浮點數</h2>
|
||||
<p>TODO</p>
|
||||
<p>Go語言提供了兩種精度的浮點數, float32 和 float64. 它們的算術規范由 IEEE754 國際標準定義, 該浮點數規范被所有現代的CPU支持.</p>
|
||||
<p>這些數值類型的范圍可以從很微小到很鉅大. 浮點數的范圍極限值可以在 matn 包找到. 常量 math.MaxFloat32 表示 float32 能表示的最大數值, 大約是 3.4e38, 對應的 math.MaxFloat64 常量大約是 1.8e308. 它們能表示的最小值近似分别是1.4e-45 和 4.9e-324.</p>
|
||||
<p>一個 float32 類型的浮點數可以提供大約6個十進製數的精度, 而 float64 則可以提供約 15個十進製數精度; 通常應該優先使用 float64 類型, 因爲 float32 類型的纍計計算誤差很容易擴散, 併且 float32 能精度表示的正整數併不是很大:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> f <span class="hljs-typename">float32</span> = <span class="hljs-number">16777216</span> <span class="hljs-comment">// 1 << 24</span>
|
||||
fmt.Println(f == f+<span class="hljs-number">1</span>) <span class="hljs-comment">// "true"!</span>
|
||||
</code></pre>
|
||||
<p>浮點數的字面值可以直接寫小數部分, 想這樣:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> e = <span class="hljs-number">2.71828</span> <span class="hljs-comment">// (approximately)</span>
|
||||
</code></pre>
|
||||
<p>小數點前面或後面的數字都可能被省略(例如 .707 或 1.). 很小或很大的數最好用科學計數法書寫, 通過e或E來指定指數部分:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> Avogadro = <span class="hljs-number">6.02214129e23</span>
|
||||
<span class="hljs-keyword">const</span> Planck = <span class="hljs-number">6.62606957e-34</span>
|
||||
</code></pre>
|
||||
<p>用 Printf 函數的 %g 參數打印浮點數, 將采用緊湊的表示形式打印, 併提供足夠的精度, 但是對應表格的數據, 使用 %e (帶指數) 或 %f 的形式打印可能更合適. 所有的這三個打印形式都可以指定打印的寬度和控製打印精度.</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">for</span> x := <span class="hljs-number">0</span>; x < <span class="hljs-number">8</span>; x++ {
|
||||
fmt.Printf(<span class="hljs-string">"x = %d e^x = %8.3f\n"</span>, x, math.Exp(<span class="hljs-typename">float64</span>(x)))
|
||||
}
|
||||
</code></pre>
|
||||
<p>上面代碼打印e的冪, 打印精度是小數點後三個小數精度和8個字符寬度:</p>
|
||||
<pre><code>x = 0 e^x = 1.000
|
||||
x = 1 e^x = 2.718
|
||||
x = 2 e^x = 7.389
|
||||
x = 3 e^x = 20.086
|
||||
x = 4 e^x = 54.598
|
||||
x = 5 e^x = 148.413
|
||||
x = 6 e^x = 403.429
|
||||
x = 7 e^x = 1096.633
|
||||
</code></pre><p>math 包中除了提供大量常用的數學函數外, 還提供了IEEE754標準中特殊數值的創建和測試: 正無窮大和負無窮大, 分别用於表示太大溢齣的數字和除零的結果; 還有 NaN 非數, 一般用於表示無效的除法操作結果 0/0 或 Sqrt(-1).</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> z <span class="hljs-typename">float64</span>
|
||||
fmt.Println(z, -z, <span class="hljs-number">1</span>/z, -<span class="hljs-number">1</span>/z, z/z) <span class="hljs-comment">// "0 -0 +Inf -Inf NaN"</span>
|
||||
</code></pre>
|
||||
<p>函數 math.IsNaN 用於測試一個數是否是非數 NaN, math.NaN 則返迴非數對應的值. 雖然可以用 math.NaN 來表示一個非法的結果, 但是測試一個結果是否是非數 NaN 則是充滿風險, 因爲 NaN 和任何數都是不相等的:</p>
|
||||
<pre><code class="lang-Go">nan := math.NaN()
|
||||
fmt.Println(nan == nan, nan < nan, nan > nan) <span class="hljs-comment">// "false false false"</span>
|
||||
</code></pre>
|
||||
<p>如果一個函數返迴的浮點數結果可能失敗, 最好的做法是用單獨的標誌報告失敗, 像這樣:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">func</span> compute() (value <span class="hljs-typename">float64</span>, ok <span class="hljs-typename">bool</span>) {
|
||||
<span class="hljs-comment">// ...</span>
|
||||
<span class="hljs-keyword">if</span> failed {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>, <span class="hljs-constant">false</span>
|
||||
}
|
||||
<span class="hljs-keyword">return</span> result, <span class="hljs-constant">true</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>接下來的程序演示了浮點計算圖形. 它是帶有兩個參數的 z = f(x, y) 函數的三維形式, 使用了可縮放矢量圖形(SVG)格式輸齣, 一個用於矢量線繪製的XML標準. 圖3.1顯示了 sin(r)/r 函數的輸齣圖形, 其中 r 是 sqrt(x<em>x+y</em>y).</p>
|
||||
<p><img src="../images/ch3-01.png" alt=""></p>
|
||||
<pre><code class="lang-Go">gopl.io/ch3/surface
|
||||
<span class="hljs-comment">// Surface computes an SVG rendering of a 3-D surface function.</span>
|
||||
<span class="hljs-keyword">package</span> main
|
||||
|
||||
<span class="hljs-keyword">import</span> (
|
||||
<span class="hljs-string">"fmt"</span>
|
||||
<span class="hljs-string">"math"</span>
|
||||
)
|
||||
|
||||
<span class="hljs-keyword">const</span> (
|
||||
width, height = <span class="hljs-number">600</span>, <span class="hljs-number">320</span> <span class="hljs-comment">// canvas size in pixels</span>
|
||||
cells = <span class="hljs-number">100</span> <span class="hljs-comment">// number of grid cells</span>
|
||||
xyrange = <span class="hljs-number">30.0</span> <span class="hljs-comment">// axis ranges (-xyrange..+xyrange)</span>
|
||||
xyscale = width / <span class="hljs-number">2</span> / xyrange <span class="hljs-comment">// pixels per x or y unit</span>
|
||||
zscale = height * <span class="hljs-number">0.4</span> <span class="hljs-comment">// pixels per z unit</span>
|
||||
angle = math.Pi / <span class="hljs-number">6</span> <span class="hljs-comment">// angle of x, y axes (=30°)</span>
|
||||
)
|
||||
|
||||
<span class="hljs-keyword">var</span> sin30, cos30 = math.Sin(angle), math.Cos(angle) <span class="hljs-comment">// sin(30°), cos(30°)</span>
|
||||
|
||||
<span class="hljs-keyword">func</span> main() {
|
||||
fmt.Printf(<span class="hljs-string">"<svg xmlns='http://www.w3.org/2000/svg' "</span>+
|
||||
<span class="hljs-string">"style='stroke: grey; fill: white; stroke-width: 0.7' "</span>+
|
||||
<span class="hljs-string">"width='%d' height='%d'>"</span>, width, height)
|
||||
<span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < cells; i++ {
|
||||
<span class="hljs-keyword">for</span> j := <span class="hljs-number">0</span>; j < cells; j++ {
|
||||
ax, ay := corner(i+<span class="hljs-number">1</span>, j)
|
||||
bx, by := corner(i, j)
|
||||
cx, cy := corner(i, j+<span class="hljs-number">1</span>)
|
||||
dx, dy := corner(i+<span class="hljs-number">1</span>, j+<span class="hljs-number">1</span>)
|
||||
fmt.Printf(<span class="hljs-string">"<polygon points='%g,%g %g,%g %g,%g %g,%g'/>\n"</span>,
|
||||
ax, ay, bx, by, cx, cy, dx, dy)
|
||||
}
|
||||
}
|
||||
fmt.Println(<span class="hljs-string">"</svg>"</span>)
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">func</span> corner(i, j <span class="hljs-typename">int</span>) (<span class="hljs-typename">float64</span>, <span class="hljs-typename">float64</span>) {
|
||||
<span class="hljs-comment">// Find point (x,y) at corner of cell (i,j).</span>
|
||||
x := xyrange * (<span class="hljs-typename">float64</span>(i)/cells - <span class="hljs-number">0.5</span>)
|
||||
y := xyrange * (<span class="hljs-typename">float64</span>(j)/cells - <span class="hljs-number">0.5</span>)
|
||||
|
||||
<span class="hljs-comment">// Compute surface height z.</span>
|
||||
z := f(x, y)
|
||||
|
||||
<span class="hljs-comment">// Project (x,y,z) isometrically onto 2-D SVG canvas (sx,sy).</span>
|
||||
sx := width/<span class="hljs-number">2</span> + (x-y)*cos30*xyscale
|
||||
sy := height/<span class="hljs-number">2</span> + (x+y)*sin30*xyscale - z*zscale
|
||||
<span class="hljs-keyword">return</span> sx, sy
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">func</span> f(x, y <span class="hljs-typename">float64</span>) <span class="hljs-typename">float64</span> {
|
||||
r := math.Hypot(x, y) <span class="hljs-comment">// distance from (0,0)</span>
|
||||
<span class="hljs-keyword">return</span> math.Sin(r) / r
|
||||
}
|
||||
</code></pre>
|
||||
<p>要註意的是 corner 返迴了兩個結果, 對應 corner 的坐標參數.</p>
|
||||
<p>要解釋程序是如何工作的需要了解基本的幾何知識, 但是我們可以跳過幾何原理, 因爲程序的重點是演示浮點運算. 程序的本質是三個不同的坐標繫中映射關繫, 如圖3.2所示. 第一個是 100x100 的二維網格, 對應整數整數坐標(i,j), 從遠處的 (0, 0) 位置開始. 我們從遠處像前面繪製, 因此遠處先繪製的多邊形有可能被前面後繪製的多邊形覆蓋.</p>
|
||||
<p>第二個坐標繫是一個三維的網格浮點坐標(x,y,z), 其中x和y是i和j的線性函數, 通過平移轉換位center的中心, 然後用xyrange繫數縮放. 高度z是函數f(x,y)的值.</p>
|
||||
<p>第三個坐標繫是一個二維的畵布, 起點(0,0)在左上角. 畵布中點的坐標用(sx, sy)表示. 我們使用等角投影將三維點</p>
|
||||
<p><img src="../images/ch3-02.png" alt=""></p>
|
||||
<p>(x,y,z) 投影到二維的畵布中. 畵布中從遠處到右邊的點對應較大的x值和較大的y值. 併且畵布中x和y值越大, 則對應的z值越小. x和y的垂直和水平縮放繫數來自30度角的正絃和餘絃值. z的縮放繫數0.4, 是一個任意選擇的參數.</p>
|
||||
<p>對於二維網格中的每一個單位, main函數計算單元的四個頂點在畵布中對應多邊形ABCD的頂點, 其中B對應(i,j)頂點位置, A, C, 和 D是相鄰的頂點, 然後輸齣SVG的繪製指令.</p>
|
||||
<p><strong>練習3.1:</strong> 如果 f 函數返迴的是無限製的 float64 值, 那麽SVG文件可能輸齣無效的<polygon></polygon>多邊形元素(雖然許多SVG渲染器會妥善處理這類問題). 脩改程序跳過無效的多邊形.</p>
|
||||
<p><strong>練習3.2:</strong> 試驗math包中其他函數的渲染圖形. 你是否能輸齣一個egg box, moguls, 或 a saddle 圖案?</p>
|
||||
<p><strong>練習3.3:</strong>根據高度給每個多邊形上色, 那樣峯值部將是紅色(#ff0000), 谷部將是藍色(#0000ff).</p>
|
||||
<p><strong>3.4:</strong> 參考1.7節Lissajous例子的函數, 構造一個web服務器, 用於計算函數麴面然後返迴SVG數據給客戶端. 服務器必鬚設置 Content-Type 頭部:</p>
|
||||
<pre><code class="lang-Go">w.Header().Set(<span class="hljs-string">"Content-Type"</span>, <span class="hljs-string">"image/svg+xml"</span>)
|
||||
</code></pre>
|
||||
<p>(這一步在Lissajous例子中不是必鬚的, 因爲服務器使用標準的PNG圖像格式, 可以根據前面的512個字節自動輸齣對應的頭部.) 允許客戶端通過HTTP請求參數設置高度, 寬度, 和顔色等參數.</p>
|
||||
|
||||
|
||||
</section>
|
||||
@@ -2074,7 +2153,7 @@
|
||||
<a href="../ch3/ch3-01.html" class="navigation navigation-prev " aria-label="Previous page: 整型"><i class="fa fa-angle-left"></i></a>
|
||||
|
||||
|
||||
<a href="../ch3/ch3-03.html" class="navigation navigation-next " aria-label="Next page: 復數"><i class="fa fa-angle-right"></i></a>
|
||||
<a href="../ch3/ch3-03.html" class="navigation navigation-next " aria-label="Next page: 複數"><i class="fa fa-angle-right"></i></a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
172
ch3/ch3-03.html
172
ch3/ch3-03.html
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>復數 | Go编程语言</title>
|
||||
<title>複數 | Go编程语言</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="3.3" data-chapter-title="復數" data-filepath="ch3/ch3-03.md" data-basepath=".." data-revision="Wed Dec 16 2015 10:54:29 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="3.3" data-chapter-title="複數" data-filepath="ch3/ch3-03.md" data-basepath=".." data-revision="Mon Dec 21 2015 12:51:02 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
<b>0.5.</b>
|
||||
|
||||
緻謝
|
||||
致謝
|
||||
</a>
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
|
||||
<b>1.3.</b>
|
||||
|
||||
査找重復的行
|
||||
査找重複的行
|
||||
</a>
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
|
||||
<b>1.4.</b>
|
||||
|
||||
GIF動畫
|
||||
GIF動畵
|
||||
</a>
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
<b>1.6.</b>
|
||||
|
||||
併髮穫取多個URL
|
||||
併發穫取多個URL
|
||||
</a>
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
|
||||
<b>3.3.</b>
|
||||
|
||||
復數
|
||||
複數
|
||||
</a>
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@
|
||||
|
||||
<b>3.4.</b>
|
||||
|
||||
佈爾型
|
||||
布爾型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@
|
||||
|
||||
<b>4.</b>
|
||||
|
||||
復閤數據類型
|
||||
複合數據類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@
|
||||
|
||||
<b>6.2.</b>
|
||||
|
||||
基於指鍼對象的方法
|
||||
基於指針對象的方法
|
||||
</a>
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
|
||||
<b>6.4.</b>
|
||||
|
||||
方法值和方法錶達式
|
||||
方法值和方法表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -953,7 +953,7 @@
|
||||
|
||||
<b>7.1.</b>
|
||||
|
||||
接口是閤約
|
||||
接口是合約
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1073,7 +1073,7 @@
|
||||
|
||||
<b>7.9.</b>
|
||||
|
||||
示例: 錶達式求值
|
||||
示例: 表達式求值
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1103,7 +1103,7 @@
|
||||
|
||||
<b>7.11.</b>
|
||||
|
||||
基於類型斷言識彆錯誤類型
|
||||
基於類型斷言識别錯誤類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1214,7 +1214,7 @@
|
||||
|
||||
<b>8.2.</b>
|
||||
|
||||
示例: 併髮的Clock服務
|
||||
示例: 併發的Clock服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1229,7 +1229,7 @@
|
||||
|
||||
<b>8.3.</b>
|
||||
|
||||
示例: 併髮的Echo服務
|
||||
示例: 併發的Echo服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1274,7 +1274,7 @@
|
||||
|
||||
<b>8.6.</b>
|
||||
|
||||
示例: 併髮的Web爬蟲
|
||||
示例: 併發的Web爬蟲
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1289,7 +1289,7 @@
|
||||
|
||||
<b>8.7.</b>
|
||||
|
||||
基於select的多路復用
|
||||
基於select的多路複用
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1304,7 +1304,7 @@
|
||||
|
||||
<b>8.8.</b>
|
||||
|
||||
示例: 併髮的字典遍歷
|
||||
示例: 併發的字典遍歷
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1319,7 +1319,7 @@
|
||||
|
||||
<b>8.9.</b>
|
||||
|
||||
併髮的退齣
|
||||
併發的退齣
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1354,7 +1354,7 @@
|
||||
|
||||
<b>9.</b>
|
||||
|
||||
基於共享變量的併髮
|
||||
基於共享變量的併發
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1415,7 +1415,7 @@
|
||||
|
||||
<b>9.4.</b>
|
||||
|
||||
內存衕步
|
||||
內存同步
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1460,7 +1460,7 @@
|
||||
|
||||
<b>9.7.</b>
|
||||
|
||||
示例: 併髮的非阻塞緩存
|
||||
示例: 併發的非阻塞緩存
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1475,7 +1475,7 @@
|
||||
|
||||
<b>9.8.</b>
|
||||
|
||||
Goroutines和綫程
|
||||
Goroutines和線程
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1748,7 +1748,7 @@
|
||||
|
||||
<b>12.1.</b>
|
||||
|
||||
為何需要反射?
|
||||
爲何需要反射?
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1793,7 +1793,7 @@
|
||||
|
||||
<b>12.4.</b>
|
||||
|
||||
示例: 編碼S錶達式
|
||||
示例: 編碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1823,7 +1823,7 @@
|
||||
|
||||
<b>12.6.</b>
|
||||
|
||||
示例: 解碼S錶達式
|
||||
示例: 解碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1975,50 +1975,14 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="14" data-path="exercise/ex.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.</b>
|
||||
|
||||
習題解答
|
||||
</a>
|
||||
|
||||
|
||||
<ul class="articles">
|
||||
|
||||
|
||||
<li class="chapter " data-level="14.1" data-path="exercise/ex-ch1.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex-ch1.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.1.</b>
|
||||
|
||||
第一章 入門
|
||||
</a>
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="15" data-path="errata.html">
|
||||
<li class="chapter " data-level="14" data-path="errata.html">
|
||||
|
||||
|
||||
<a href="../errata.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>15.</b>
|
||||
<b>14.</b>
|
||||
|
||||
勘誤
|
||||
</a>
|
||||
@@ -2059,8 +2023,80 @@
|
||||
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h2 id="33-復數">3.3. 復數</h2>
|
||||
<p>TODO</p>
|
||||
<h2 id="33-複數">3.3. 複數</h2>
|
||||
<p>Go提供了兩種精度的複數類似, complex64 和 complex128, 分别對應 float32 和 float64精度. 內置的 complex 函數用於構建複數, 內建的 real 和 imag 函數返迴複數的實部和虛部:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> x <span class="hljs-typename">complex128</span> = <span class="hljs-built_in">complex</span>(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>) <span class="hljs-comment">// 1+2i</span>
|
||||
<span class="hljs-keyword">var</span> y <span class="hljs-typename">complex128</span> = <span class="hljs-built_in">complex</span>(<span class="hljs-number">3</span>, <span class="hljs-number">4</span>) <span class="hljs-comment">// 3+4i</span>
|
||||
fmt.Println(x*y) <span class="hljs-comment">// "(-5+10i)"</span>
|
||||
fmt.Println(<span class="hljs-built_in">real</span>(x*y)) <span class="hljs-comment">// "-5"</span>
|
||||
fmt.Println(<span class="hljs-built_in">imag</span>(x*y)) <span class="hljs-comment">// "10"</span>
|
||||
</code></pre>
|
||||
<p>如果一個浮點數面值或一個十進製整數面值後面跟着一個i, 例如 3.141592i 或 2i, 它將構成一個複數的虛部, 複數的實部是0:</p>
|
||||
<pre><code class="lang-Go">fmt.Println(<span class="hljs-number">1i</span> * <span class="hljs-number">1i</span>) <span class="hljs-comment">// "(-1+0i)", i^2 = -1</span>
|
||||
</code></pre>
|
||||
<p>在常量算術規則下, 一個複數常量可以加到另一個常量(整數或浮點數, 實部或虛部), 我們可以用自然的方式寫複數, 就像 1+2i, 或與之等價的寫法 2i+1. 上面x和y的聲明語句還可以簡化:</p>
|
||||
<pre><code class="lang-Go">x := <span class="hljs-number">1</span> + <span class="hljs-number">2i</span>
|
||||
y := <span class="hljs-number">3</span> + <span class="hljs-number">4i</span>
|
||||
</code></pre>
|
||||
<p>複數也可以用 == 和 != 進行相等比較. 隻有兩個複數的實部和虛部都相等的時候它們纔是相等的.</p>
|
||||
<p>math/cmplx 包提供了複數處理的許多函數, 例如求複數的平方根函數和求冪函數.</p>
|
||||
<pre><code class="lang-Go">fmt.Println(cmplx.Sqrt(-<span class="hljs-number">1</span>)) <span class="hljs-comment">// "(0+1i)"</span>
|
||||
</code></pre>
|
||||
<p>下面的程序使用complex128複數算法來生成一個Mandelbrot圖像.</p>
|
||||
<pre><code class="lang-Go">gopl.io/ch3/mandelbrot
|
||||
|
||||
<span class="hljs-comment">// Mandelbrot emits a PNG image of the Mandelbrot fractal.</span>
|
||||
<span class="hljs-keyword">package</span> main
|
||||
|
||||
<span class="hljs-keyword">import</span> (
|
||||
<span class="hljs-string">"image"</span>
|
||||
<span class="hljs-string">"image/color"</span>
|
||||
<span class="hljs-string">"image/png"</span>
|
||||
<span class="hljs-string">"math/cmplx"</span>
|
||||
<span class="hljs-string">"os"</span>
|
||||
)
|
||||
|
||||
|
||||
<span class="hljs-keyword">func</span> main() {
|
||||
<span class="hljs-keyword">const</span> (
|
||||
xmin, ymin, xmax, ymax = -<span class="hljs-number">2</span>, -<span class="hljs-number">2</span>, +<span class="hljs-number">2</span>, +<span class="hljs-number">2</span>
|
||||
width, height = <span class="hljs-number">1024</span>, <span class="hljs-number">1024</span>
|
||||
)
|
||||
|
||||
img := image.NewRGBA(image.Rect(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, width, height))
|
||||
<span class="hljs-keyword">for</span> py := <span class="hljs-number">0</span>; py < height; py++ {
|
||||
y := <span class="hljs-typename">float64</span>(py)/height*(ymax-ymin) + ymin
|
||||
<span class="hljs-keyword">for</span> px := <span class="hljs-number">0</span>; px < width; px++ {
|
||||
x := <span class="hljs-typename">float64</span>(px)/width*(xmax-xmin) + xmin
|
||||
z := <span class="hljs-built_in">complex</span>(x, y)
|
||||
<span class="hljs-comment">// Image point (px, py) represents complex value z.</span>
|
||||
img.Set(px, py, mandelbrot(z))
|
||||
}
|
||||
}
|
||||
png.Encode(os.Stdout, img) <span class="hljs-comment">// <span class="hljs-doctag">NOTE:</span> ignoring errors</span>
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">func</span> mandelbrot(z <span class="hljs-typename">complex128</span>) color.Color {
|
||||
<span class="hljs-keyword">const</span> iterations = <span class="hljs-number">200</span>
|
||||
<span class="hljs-keyword">const</span> contrast = <span class="hljs-number">15</span>
|
||||
|
||||
<span class="hljs-keyword">var</span> v <span class="hljs-typename">complex128</span>
|
||||
<span class="hljs-keyword">for</span> n := <span class="hljs-typename">uint8</span>(<span class="hljs-number">0</span>); n < iterations; n++ {
|
||||
v = v*v + z
|
||||
<span class="hljs-keyword">if</span> cmplx.Abs(v) > <span class="hljs-number">2</span> {
|
||||
<span class="hljs-keyword">return</span> color.Gray{<span class="hljs-number">255</span> - contrast*n}
|
||||
}
|
||||
}
|
||||
<span class="hljs-keyword">return</span> color.Black
|
||||
}
|
||||
</code></pre>
|
||||
<p>遍歷1024x1024圖像每個點的兩個嵌套的循環對應 -2 到 +2 區間的複數平面. 程序反複測試每個點對應複數值平方值加一個增量值對應的點是否超齣半徑爲2的圓. 如果超過了, 通過根據逃逸的迭代次數對應的灰度顔色來代替. 如果不是, 該點屬於Mandelbrot集合, 使用黑色顔色標記. 最終程序將生成的PNG格式分形圖像圖像輸齣到標準輸齣, 如圖3.3所示.</p>
|
||||
<p><strong>練習3.5:</strong> 實現一個綵色的Mandelbrot圖像, 使用 image.NewRGBA 創建圖像, 使用 color.RGBA 或 color.YCbCr 生成顔色.</p>
|
||||
<p><strong>練習3.6:</strong> 超采樣技術可以降低每個像素對計算顔色值和平均值的影響. 簡單的方法是將每個像素分層四個子像素, 實現它.</p>
|
||||
<p><strong>練習3.7:</strong> 另一個生成分形圖像的方式是使用牛頓法來求解一個複數方程, 例如 z^4 − 1 = 0. 每個起點到四個根的迭代次數對應陰影的灰度. 方程根對應的點用顔色表示.</p>
|
||||
<p><img src="../images/ch3-03.png" alt=""></p>
|
||||
<p><strong>練習3.8:</strong> 通過提高精度來生成更多級别的分形. 使用四種不同精度類型的數字實現相同的分形: complex64, complex128, big.Float, and big.Rat. (後面兩種類型在 math/big 包聲明. Float是有指定限精度的浮點數; Rat是無效精度的有理數.) 它們間的性能和內存使用對比如何? 當渲染圖可見時縮放的級别是多少?</p>
|
||||
<p><strong>練習3.9:</strong> 編寫一個web服務器, 用於給客戶端生成分形的圖像. 運行客戶端用過HTTP參數參數指定x,y和zoom參數.</p>
|
||||
|
||||
|
||||
</section>
|
||||
@@ -2074,7 +2110,7 @@
|
||||
<a href="../ch3/ch3-02.html" class="navigation navigation-prev " aria-label="Previous page: 浮點數"><i class="fa fa-angle-left"></i></a>
|
||||
|
||||
|
||||
<a href="../ch3/ch3-04.html" class="navigation navigation-next " aria-label="Next page: 佈爾型"><i class="fa fa-angle-right"></i></a>
|
||||
<a href="../ch3/ch3-04.html" class="navigation navigation-next " aria-label="Next page: 布爾型"><i class="fa fa-angle-right"></i></a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
130
ch3/ch3-04.html
130
ch3/ch3-04.html
@@ -5,7 +5,7 @@
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>佈爾型 | Go编程语言</title>
|
||||
<title>布爾型 | Go编程语言</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="description" content="">
|
||||
<meta name="generator" content="GitBook 2.5.2">
|
||||
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="3.4" data-chapter-title="佈爾型" data-filepath="ch3/ch3-04.md" data-basepath=".." data-revision="Wed Dec 16 2015 10:54:29 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="3.4" data-chapter-title="布爾型" data-filepath="ch3/ch3-04.md" data-basepath=".." data-revision="Mon Dec 21 2015 12:51:02 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
<b>0.5.</b>
|
||||
|
||||
緻謝
|
||||
致謝
|
||||
</a>
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
|
||||
<b>1.3.</b>
|
||||
|
||||
査找重復的行
|
||||
査找重複的行
|
||||
</a>
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
|
||||
<b>1.4.</b>
|
||||
|
||||
GIF動畫
|
||||
GIF動畵
|
||||
</a>
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
<b>1.6.</b>
|
||||
|
||||
併髮穫取多個URL
|
||||
併發穫取多個URL
|
||||
</a>
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
|
||||
<b>3.3.</b>
|
||||
|
||||
復數
|
||||
複數
|
||||
</a>
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@
|
||||
|
||||
<b>3.4.</b>
|
||||
|
||||
佈爾型
|
||||
布爾型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@
|
||||
|
||||
<b>4.</b>
|
||||
|
||||
復閤數據類型
|
||||
複合數據類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@
|
||||
|
||||
<b>6.2.</b>
|
||||
|
||||
基於指鍼對象的方法
|
||||
基於指針對象的方法
|
||||
</a>
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
|
||||
<b>6.4.</b>
|
||||
|
||||
方法值和方法錶達式
|
||||
方法值和方法表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -953,7 +953,7 @@
|
||||
|
||||
<b>7.1.</b>
|
||||
|
||||
接口是閤約
|
||||
接口是合約
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1073,7 +1073,7 @@
|
||||
|
||||
<b>7.9.</b>
|
||||
|
||||
示例: 錶達式求值
|
||||
示例: 表達式求值
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1103,7 +1103,7 @@
|
||||
|
||||
<b>7.11.</b>
|
||||
|
||||
基於類型斷言識彆錯誤類型
|
||||
基於類型斷言識别錯誤類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1214,7 +1214,7 @@
|
||||
|
||||
<b>8.2.</b>
|
||||
|
||||
示例: 併髮的Clock服務
|
||||
示例: 併發的Clock服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1229,7 +1229,7 @@
|
||||
|
||||
<b>8.3.</b>
|
||||
|
||||
示例: 併髮的Echo服務
|
||||
示例: 併發的Echo服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1274,7 +1274,7 @@
|
||||
|
||||
<b>8.6.</b>
|
||||
|
||||
示例: 併髮的Web爬蟲
|
||||
示例: 併發的Web爬蟲
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1289,7 +1289,7 @@
|
||||
|
||||
<b>8.7.</b>
|
||||
|
||||
基於select的多路復用
|
||||
基於select的多路複用
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1304,7 +1304,7 @@
|
||||
|
||||
<b>8.8.</b>
|
||||
|
||||
示例: 併髮的字典遍歷
|
||||
示例: 併發的字典遍歷
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1319,7 +1319,7 @@
|
||||
|
||||
<b>8.9.</b>
|
||||
|
||||
併髮的退齣
|
||||
併發的退齣
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1354,7 +1354,7 @@
|
||||
|
||||
<b>9.</b>
|
||||
|
||||
基於共享變量的併髮
|
||||
基於共享變量的併發
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1415,7 +1415,7 @@
|
||||
|
||||
<b>9.4.</b>
|
||||
|
||||
內存衕步
|
||||
內存同步
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1460,7 +1460,7 @@
|
||||
|
||||
<b>9.7.</b>
|
||||
|
||||
示例: 併髮的非阻塞緩存
|
||||
示例: 併發的非阻塞緩存
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1475,7 +1475,7 @@
|
||||
|
||||
<b>9.8.</b>
|
||||
|
||||
Goroutines和綫程
|
||||
Goroutines和線程
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1748,7 +1748,7 @@
|
||||
|
||||
<b>12.1.</b>
|
||||
|
||||
為何需要反射?
|
||||
爲何需要反射?
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1793,7 +1793,7 @@
|
||||
|
||||
<b>12.4.</b>
|
||||
|
||||
示例: 編碼S錶達式
|
||||
示例: 編碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1823,7 +1823,7 @@
|
||||
|
||||
<b>12.6.</b>
|
||||
|
||||
示例: 解碼S錶達式
|
||||
示例: 解碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1975,50 +1975,14 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="14" data-path="exercise/ex.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.</b>
|
||||
|
||||
習題解答
|
||||
</a>
|
||||
|
||||
|
||||
<ul class="articles">
|
||||
|
||||
|
||||
<li class="chapter " data-level="14.1" data-path="exercise/ex-ch1.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex-ch1.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.1.</b>
|
||||
|
||||
第一章 入門
|
||||
</a>
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="15" data-path="errata.html">
|
||||
<li class="chapter " data-level="14" data-path="errata.html">
|
||||
|
||||
|
||||
<a href="../errata.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>15.</b>
|
||||
<b>14.</b>
|
||||
|
||||
勘誤
|
||||
</a>
|
||||
@@ -2059,8 +2023,38 @@
|
||||
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h2 id="34-佈爾型">3.4. 佈爾型</h2>
|
||||
<p>TODO</p>
|
||||
<h2 id="34-布爾型">3.4. 布爾型</h2>
|
||||
<p>一個布爾類型的值隻有兩種 true 和 false. if 和 for 語句的條件部分都是布爾類型的值, 併且 == 和 < 等比較操作也會産生布爾型的值. 一元操作符 <code>!</code> 對應邏輯非操作, 因此 <code>!true</code> 的值爲 <code>false</code>, 也可以説是 <code>(!true==false)==true</code>, 雖然表達方式不一樣, 不過我們一般會采用簡潔的布爾表達式, 就像用 x 來表示 <code>x==true</code>.</p>
|
||||
<p>布爾值可以和 && (AND) 和 || (OR) 操作符結合, 併且可能會有短路行爲: 如果運算符左邊值已經可以確定整個布爾表達式的值, 那麽運算符右邊的值將不在被評估, 因此下面的表達式總是安全的:</p>
|
||||
<pre><code class="lang-Go">s != <span class="hljs-string">""</span> && s[<span class="hljs-number">0</span>] == <span class="hljs-string">'x'</span>
|
||||
</code></pre>
|
||||
<p>其中 s[0] 應用於空字符串會導致 panic 異常.</p>
|
||||
<p>因爲 <code>&&</code> 的優先級比 <code>||</code> 高 (助記: <code>&&</code> 對應邏輯乘法, <code>||</code> 對應邏輯加法, 乘法比加法優先級要高), 下面形式的布爾表達式是不需要加小括弧的:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">if</span> <span class="hljs-string">'a'</span> <= c && c <= <span class="hljs-string">'z'</span> ||
|
||||
<span class="hljs-string">'A'</span> <= c && c <= <span class="hljs-string">'Z'</span> ||
|
||||
<span class="hljs-string">'0'</span> <= c && c <= <span class="hljs-string">'9'</span> {
|
||||
<span class="hljs-comment">// ...ASCII letter or digit...</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>布爾值併不會隱式轉換爲數字值0或1, 反之亦然. 必鬚使用一個顯式的if語句輔助轉換:</p>
|
||||
<pre><code class="lang-Go">i := <span class="hljs-number">0</span>
|
||||
<span class="hljs-keyword">if</span> b {
|
||||
i = <span class="hljs-number">1</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>如果需要經常做類似的轉換, 包裝成一個函數會更方便:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-comment">// btoi returns 1 if b is true and 0 if false.</span>
|
||||
<span class="hljs-keyword">func</span> btoi(b <span class="hljs-typename">bool</span>) <span class="hljs-typename">int</span> {
|
||||
<span class="hljs-keyword">if</span> b {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
|
||||
}
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>數字到布爾型的逆轉換則非常簡單, 不過爲了保持對稱, 我們也可以包裝一個函數:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-comment">// itob reports whether i is non-zero.</span>
|
||||
<span class="hljs-keyword">func</span> itob(i <span class="hljs-typename">int</span>) <span class="hljs-typename">bool</span> { <span class="hljs-keyword">return</span> i != <span class="hljs-number">0</span> }
|
||||
</code></pre>
|
||||
|
||||
|
||||
</section>
|
||||
@@ -2071,7 +2065,7 @@
|
||||
</div>
|
||||
|
||||
|
||||
<a href="../ch3/ch3-03.html" class="navigation navigation-prev " aria-label="Previous page: 復數"><i class="fa fa-angle-left"></i></a>
|
||||
<a href="../ch3/ch3-03.html" class="navigation navigation-prev " aria-label="Previous page: 複數"><i class="fa fa-angle-left"></i></a>
|
||||
|
||||
|
||||
<a href="../ch3/ch3-05.html" class="navigation navigation-next " aria-label="Next page: 字符串"><i class="fa fa-angle-right"></i></a>
|
||||
|
||||
381
ch3/ch3-05.html
381
ch3/ch3-05.html
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="3.5" data-chapter-title="字符串" data-filepath="ch3/ch3-05.md" data-basepath=".." data-revision="Wed Dec 16 2015 10:54:29 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="3.5" data-chapter-title="字符串" data-filepath="ch3/ch3-05.md" data-basepath=".." data-revision="Mon Dec 21 2015 12:51:02 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
<b>0.5.</b>
|
||||
|
||||
緻謝
|
||||
致謝
|
||||
</a>
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
|
||||
<b>1.3.</b>
|
||||
|
||||
査找重復的行
|
||||
査找重複的行
|
||||
</a>
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
|
||||
<b>1.4.</b>
|
||||
|
||||
GIF動畫
|
||||
GIF動畵
|
||||
</a>
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
<b>1.6.</b>
|
||||
|
||||
併髮穫取多個URL
|
||||
併發穫取多個URL
|
||||
</a>
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
|
||||
<b>3.3.</b>
|
||||
|
||||
復數
|
||||
複數
|
||||
</a>
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@
|
||||
|
||||
<b>3.4.</b>
|
||||
|
||||
佈爾型
|
||||
布爾型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@
|
||||
|
||||
<b>4.</b>
|
||||
|
||||
復閤數據類型
|
||||
複合數據類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@
|
||||
|
||||
<b>6.2.</b>
|
||||
|
||||
基於指鍼對象的方法
|
||||
基於指針對象的方法
|
||||
</a>
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
|
||||
<b>6.4.</b>
|
||||
|
||||
方法值和方法錶達式
|
||||
方法值和方法表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -953,7 +953,7 @@
|
||||
|
||||
<b>7.1.</b>
|
||||
|
||||
接口是閤約
|
||||
接口是合約
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1073,7 +1073,7 @@
|
||||
|
||||
<b>7.9.</b>
|
||||
|
||||
示例: 錶達式求值
|
||||
示例: 表達式求值
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1103,7 +1103,7 @@
|
||||
|
||||
<b>7.11.</b>
|
||||
|
||||
基於類型斷言識彆錯誤類型
|
||||
基於類型斷言識别錯誤類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1214,7 +1214,7 @@
|
||||
|
||||
<b>8.2.</b>
|
||||
|
||||
示例: 併髮的Clock服務
|
||||
示例: 併發的Clock服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1229,7 +1229,7 @@
|
||||
|
||||
<b>8.3.</b>
|
||||
|
||||
示例: 併髮的Echo服務
|
||||
示例: 併發的Echo服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1274,7 +1274,7 @@
|
||||
|
||||
<b>8.6.</b>
|
||||
|
||||
示例: 併髮的Web爬蟲
|
||||
示例: 併發的Web爬蟲
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1289,7 +1289,7 @@
|
||||
|
||||
<b>8.7.</b>
|
||||
|
||||
基於select的多路復用
|
||||
基於select的多路複用
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1304,7 +1304,7 @@
|
||||
|
||||
<b>8.8.</b>
|
||||
|
||||
示例: 併髮的字典遍歷
|
||||
示例: 併發的字典遍歷
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1319,7 +1319,7 @@
|
||||
|
||||
<b>8.9.</b>
|
||||
|
||||
併髮的退齣
|
||||
併發的退齣
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1354,7 +1354,7 @@
|
||||
|
||||
<b>9.</b>
|
||||
|
||||
基於共享變量的併髮
|
||||
基於共享變量的併發
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1415,7 +1415,7 @@
|
||||
|
||||
<b>9.4.</b>
|
||||
|
||||
內存衕步
|
||||
內存同步
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1460,7 +1460,7 @@
|
||||
|
||||
<b>9.7.</b>
|
||||
|
||||
示例: 併髮的非阻塞緩存
|
||||
示例: 併發的非阻塞緩存
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1475,7 +1475,7 @@
|
||||
|
||||
<b>9.8.</b>
|
||||
|
||||
Goroutines和綫程
|
||||
Goroutines和線程
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1748,7 +1748,7 @@
|
||||
|
||||
<b>12.1.</b>
|
||||
|
||||
為何需要反射?
|
||||
爲何需要反射?
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1793,7 +1793,7 @@
|
||||
|
||||
<b>12.4.</b>
|
||||
|
||||
示例: 編碼S錶達式
|
||||
示例: 編碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1823,7 +1823,7 @@
|
||||
|
||||
<b>12.6.</b>
|
||||
|
||||
示例: 解碼S錶達式
|
||||
示例: 解碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1975,50 +1975,14 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="14" data-path="exercise/ex.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.</b>
|
||||
|
||||
習題解答
|
||||
</a>
|
||||
|
||||
|
||||
<ul class="articles">
|
||||
|
||||
|
||||
<li class="chapter " data-level="14.1" data-path="exercise/ex-ch1.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex-ch1.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.1.</b>
|
||||
|
||||
第一章 入門
|
||||
</a>
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="15" data-path="errata.html">
|
||||
<li class="chapter " data-level="14" data-path="errata.html">
|
||||
|
||||
|
||||
<a href="../errata.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>15.</b>
|
||||
<b>14.</b>
|
||||
|
||||
勘誤
|
||||
</a>
|
||||
@@ -2060,7 +2024,292 @@
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h2 id="35-字符串">3.5. 字符串</h2>
|
||||
<p>TODO</p>
|
||||
<p>一個字符串是一個不可改變的字節序列. 字符串可以包含任意的數據, 包括字節值0, 但是通常包含人類可讀的文本. 文本字符串通常被解釋爲采用UTF8編碼的Unicode碼點(rune)序列, 我們稍後會詳細討論這個問題.</p>
|
||||
<p>內置的 len 函數可以返迴一個字符串的字節數目(不是rune字符數目), 索引操作 s[i] 返迴第i個字節的字節值, i 必鬚滿足 0 ≤ i< len(s) 條件約束.</p>
|
||||
<pre><code class="lang-Go">s := <span class="hljs-string">"hello, world"</span>
|
||||
fmt.Println(<span class="hljs-built_in">len</span>(s)) <span class="hljs-comment">// "12"</span>
|
||||
fmt.Println(s[<span class="hljs-number">0</span>], s[<span class="hljs-number">7</span>]) <span class="hljs-comment">// "104 119" ('h' and 'w')</span>
|
||||
</code></pre>
|
||||
<p>Attempting to access a byte outside this range results in a panic:</p>
|
||||
<p>如果視圖訪問超齣字符串范圍的字節將會導致panic異常:</p>
|
||||
<pre><code class="lang-Go">c := s[<span class="hljs-built_in">len</span>(s)] <span class="hljs-comment">// panic: index out of range</span>
|
||||
</code></pre>
|
||||
<p>第i個字節併不一定是字符串的第i個字符, 因此對於非ASCII字符的UTF8編碼會要兩個或多個字節. 我們簡單説下字符的工作方式.</p>
|
||||
<p>子字符串操作s[i:j]基於原始的s字符串的第i個字節開始到第j個字節(併不包含j本身)生成一個新字符串. 生成的子字符串將包含 j-i 個字節.</p>
|
||||
<pre><code class="lang-Go">fmt.Println(s[<span class="hljs-number">0</span>:<span class="hljs-number">5</span>]) <span class="hljs-comment">// "hello"</span>
|
||||
</code></pre>
|
||||
<p>同樣, 如果索引超齣字符串范圍或者j小於i的話將導致panic異常.</p>
|
||||
<p>不管i還是j都可能被忽略, 當它們被忽略時將采用0作爲開始位置, 采用 len(s) 作爲接受的位置.</p>
|
||||
<pre><code class="lang-Go">fmt.Println(s[:<span class="hljs-number">5</span>]) <span class="hljs-comment">// "hello"</span>
|
||||
fmt.Println(s[<span class="hljs-number">7</span>:]) <span class="hljs-comment">// "world"</span>
|
||||
fmt.Println(s[:]) <span class="hljs-comment">// "hello, world"</span>
|
||||
</code></pre>
|
||||
<p>其中 + 操作符將兩個字符串鏈接構造一個新字符串:</p>
|
||||
<pre><code class="lang-Go">fmt.Println(<span class="hljs-string">"goodbye"</span> + s[<span class="hljs-number">5</span>:]) <span class="hljs-comment">// "goodbye, world"</span>
|
||||
</code></pre>
|
||||
<p>字符串可以用 == 和 < 進行比較; 比較通過逐個字節比較完成的, 因此比較的結果是字符串自然編碼的順序.</p>
|
||||
<p>字符串的值是不可變的: 一個字符串包含的字節序列永遠不會被改變, 當然我們也可以給一個字符串變量分配一個新字符串值. 可以像下面這樣將一個字符串追加到另一個字符串</p>
|
||||
<pre><code class="lang-Go">s := <span class="hljs-string">"left foot"</span>
|
||||
t := s
|
||||
s += <span class="hljs-string">", right foot"</span>
|
||||
</code></pre>
|
||||
<p>這併不會導致原始的字符串值被改變, 但是 s 將因爲 += 語句持有一個新的字符串值, 但是 t 依然是包含原先的字符串值.</p>
|
||||
<pre><code class="lang-Go">fmt.Println(s) <span class="hljs-comment">// "left foot, right foot"</span>
|
||||
fmt.Println(t) <span class="hljs-comment">// "left foot"</span>
|
||||
</code></pre>
|
||||
<p>因爲字符串是不可脩改的, 因此嚐試脩改字符串內部數據的操作是被禁止的:</p>
|
||||
<pre><code class="lang-Go">s[<span class="hljs-number">0</span>] = <span class="hljs-string">'L'</span> <span class="hljs-comment">// compile error: cannot assign to s[0]</span>
|
||||
</code></pre>
|
||||
<p>不變性意味如果兩個字符串共享相同的底層數據是安全的, 這使得複製任何長度的字符串代價是低廉的. 同樣, 一個字符串 s 和對應的子字符串 s[7:] 也可以安全地共享相同的內存, 因此字符串切片操作代價也是低廉的. 在這兩種情況下都沒有必要分配新的內存. 圖3.4 演示了一個字符串和兩個字串共享相同的底層數據.</p>
|
||||
<h3 id="351-字符串面值">3.5.1. 字符串面值</h3>
|
||||
<p>字符串值也可以用字符串面值方式編寫, 隻要將一繫列字節序列包含在雙引號卽可:</p>
|
||||
<pre><code>"Hello, 世界"
|
||||
</code></pre><p><img src="../images/ch3-04.png" alt=""></p>
|
||||
<p>因爲Go語言源文件總是用UTF8編碼, 併且Go的文本字符串也以UTF8編碼的方式處理, 我們可以將Unicode碼點也寫到字符串面值中.</p>
|
||||
<p>在一個雙引號包含的字符串面值中, 可以用以反斜槓\開頭的轉義序列插入任意的數據. 下面換行, 迴車和 製表符等常見的ASCII控製代碼的轉義方式:</p>
|
||||
<pre><code>\a 響鈴
|
||||
\b 退格
|
||||
\f 換頁
|
||||
\n 換行
|
||||
\r 迴車
|
||||
\t 製表符
|
||||
\v 垂直製表符
|
||||
\' 單引號 (隻用在 '\'' 形式的rune符號面值中)
|
||||
\" 雙引號 (隻用在 "..." 形式的字符串面值中)
|
||||
\\ 反斜槓
|
||||
</code></pre><p>可以通過十六進製或八進製轉義在字符串面值包含任意的字節. 一個十六進製的轉義是 \xhh, 其中兩個h表示十六進製數字(大寫或小寫都可以). 一個八進製轉義是 \ooo, 包含三個八進製的o數字(0到7), 但是不能超過\377. 每一個單一的字節表達一個特定的值. 稍後我們將看到如何將一個Unicode碼點寫到字符串面值中.</p>
|
||||
<p>一個原生的字符串面值形式是 <code>...</code>, 使用反引號 ``` 代替雙引號. 在原生的字符串面值中, 沒有轉義操作; 全部的內容都是字面的意思, 包含退格和換行, 因此一個程序中的原生字符串面值可能跨越多行. 唯一的特殊處理是是刪除迴車以保證在所有平颱上的值都是一樣的, 包括那些把迴車也放入文本文件的繫統.</p>
|
||||
<p>原生字符串面值用於編寫正則表達式會很方便, 因爲正則表達式往往會包含很多反斜槓. 原生字符串面值同時廣泛應用於HTML模闆, JSON面值, 命令行提示信息, 以及那些需要擴展到多行的場景.</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> GoUsage = <span class="hljs-string">`Go is a tool for managing Go source code.
|
||||
|
||||
Usage:
|
||||
go command [arguments]
|
||||
...`</span>
|
||||
</code></pre>
|
||||
<h3 id="352-unicode">3.5.2. Unicode</h3>
|
||||
<p>在很久以前, 世界比較簡單的, 起碼計算機就隻有一個ASCII字符集: 美國信息交換標準代碼. ASCII, 更準確地説是美國的ASCII, 使用 7bit 來表示 128 個字符: 包含英文字母的大小寫, 數字, 各種標點符號和設置控製符. 對於早期的計算機程序, 這些足夠了, 但是這也導致了世界上很多其他地區的用戶無法直接使用自己的書寫繫統. 隨着互聯網的發展, 混合多種語言的數據變了很常見. 如何有效處理這些包含了各種語言的豐富多樣的數據呢?</p>
|
||||
<p>答案就是使用Unicode(unicode.org), 它收集了這個世界上所有的書寫繫統, 包括重音符號和其他變音符號, 製表符和迴車符, 還有很多神祕符號, 每個符號都分配一個Unicode碼點, Unicode碼點對應Go語言中的rune類型.</p>
|
||||
<p>第八版本的Unicode標準收集了超過120,000個字符, 涵蓋超過100種語言. 這些在計算機程序和數據中是如何體現的那? 通用的表示一個Unicode碼點的數據類型是int32, 也就是Go語言中rune對應的類型; 它的同義詞rune符文正是這個意思.</p>
|
||||
<p>我們可以將一個符文序列表示爲一個int32序列. 這種編碼方式叫UTF-32或UCS-4, 每個Unicode碼點都使用同樣的大小32bit來表示. 這種方式比較簡單統一, 它會浪費很多存儲空間, 因爲大數據計算機可讀的文本是ASCII字符, 本來每個ASCII字符隻需要8bit或1字節就能表示. 卽使是常用的字符也遠少於65,536個, 也就是説用16bit編碼方式就能表達常用字符. 但是, 還有更好的編碼方法嗎?</p>
|
||||
<h3 id="353-utf8">3.5.3. UTF-8</h3>
|
||||
<p>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碼點也是采用類似的策略處理.</p>
|
||||
<pre><code>0xxxxxx runes 0-127 (ASCII)
|
||||
11xxxxx 10xxxxxx 128-2047 (values <128 unused)
|
||||
110xxxx 10xxxxxx 10xxxxxx 2048-65535 (values <2048 unused)
|
||||
1110xxx 10xxxxxx 10xxxxxx 10xxxxxx 65536-0x10ffff (other values unused)
|
||||
</code></pre><p>變長的編碼無法直接通過索引來訪問第n個字符, 但是UTF8穫得了很多額外的優點. 首先UTF8編碼比較緊湊, 兼容ASCII, 併且可以自動同步: 它可以通過向前迴朔最多2個字節就能確定當前字符編碼的開始字節的位置. 它也是一個前綴編碼, 所以當從左向右解碼時不會有任何歧義也併不需要向前査看. 沒有任何字符的編碼是其它字符編碼的子串, 或是其它編碼序列的字串, 因此蒐索一個字符時隻要蒐索它的字節編碼序列卽可, 不用擔心前後的上下文會對蒐索結果産生榦擾. 同時UTF8編碼的順序和Unicode碼點的順序一致, 因此可以直接排序UTF8編碼序列. 同業也沒有嵌入的NUL(0)字節, 可以很好地兼容那些使用NUL作爲字符串結尾的編程語言.</p>
|
||||
<p>Go的源文件采用UTF8編碼, 併且Go處理UTF8編碼的文本也很齣色. unicode 包提供了諸多處理 rune 字符相關功能的函數函數(區分字母和數組, 或者是字母的大寫和小寫轉換等), unicode/utf8 包了提供了rune 字符序列的UTF8編碼和解碼的功能.</p>
|
||||
<p>有很多Unicode字符很難直接從鍵盤輸入, 併且很多字符有着相似的結構; 有一些甚至是不可見的字符. Go字符串面值中的Unicode轉義字符讓我們可以通過Unicode碼點輸入特殊的字符. 有兩種形式, \uhhhh 對應16bit的碼點值, \Uhhhhhhhh 對應32bit的碼點值, 其中h是一個十六進製數字; 一般很少需要使用32bit的形式. 每一個對應碼點的UTF8編碼. 例如: 下面的字母串面值都表示相同的值:</p>
|
||||
<pre><code>"世界"
|
||||
"\xe4\xb8\x96\xe7\x95\x8c"
|
||||
"\u4e16\u754c"
|
||||
"\U00004e16\U0000754c"
|
||||
</code></pre><p>上面三個轉義序列爲第一個字符串提供替代寫法, 但是它們的值都是相同的.</p>
|
||||
<p>Unicode轉義也可以使用在rune字符中. 下面三個字符是等價的:</p>
|
||||
<pre><code>'世' '\u4e16' '\U00004e16'
|
||||
</code></pre><p>對於小於256碼點值可以寫在一個十六進製轉義字節中, 例如 '\x41' 對應 'A' 字符, 但是對於更大的碼點則必鬚使用 \u 或 \U 轉義形式. 因此, '\xe4\xb8\x96' 併不是一個合法的rune字符, 雖然這三個字節對應一個有效的UTF8編碼的碼點.</p>
|
||||
<p>得意於UTF8優良的設計, 諸多字符串操作都不需要解碼. 我們可以不用解碼直接測試一個字符串是否是另一個字符串的前綴:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">func</span> HasPrefix(s, prefix <span class="hljs-typename">string</span>) <span class="hljs-typename">bool</span> {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-built_in">len</span>(s) >= <span class="hljs-built_in">len</span>(prefix) && s[:<span class="hljs-built_in">len</span>(prefix)] == prefix
|
||||
}
|
||||
</code></pre>
|
||||
<p>或者是後綴測試:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">func</span> HasSuffix(s, suffix <span class="hljs-typename">string</span>) <span class="hljs-typename">bool</span> {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-built_in">len</span>(s) >= <span class="hljs-built_in">len</span>(suffix) && s[<span class="hljs-built_in">len</span>(s)-<span class="hljs-built_in">len</span>(suffix):] == suffix
|
||||
}
|
||||
</code></pre>
|
||||
<p>或者是包含子串測試:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">func</span> Contains(s, substr <span class="hljs-typename">string</span>) <span class="hljs-typename">bool</span> {
|
||||
<span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-built_in">len</span>(s); i++ {
|
||||
<span class="hljs-keyword">if</span> HasPrefix(s[i:], substr) {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-constant">true</span>
|
||||
}
|
||||
}
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-constant">false</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>對於UTF8編碼後文本的處理和原始的字節處理邏輯一樣. 但是對應很多其它編碼則併不是這樣的. (上面的函數都來自 strings 字符串處理包, 雖然它們的實現包含了一個用哈希技術優化的 Contains 實現.)</p>
|
||||
<p>另以方面, 如果我們眞的關心每個Unicode字符, 我們可以使用其它機製. 考慮前面的第一個例子中的字符串, 它包混合了中西兩種字符. 圖3.5展示了它的內存表示形式. 字符串包含13個字節, 以UTF8形式編碼, 但是隻對應9個Unicode字符:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">import</span> <span class="hljs-string">"unicode/utf8"</span>
|
||||
|
||||
s := <span class="hljs-string">"Hello, 世界"</span>
|
||||
fmt.Println(<span class="hljs-built_in">len</span>(s)) <span class="hljs-comment">// "13"</span>
|
||||
fmt.Println(utf8.RuneCountInString(s)) <span class="hljs-comment">// "9"</span>
|
||||
</code></pre>
|
||||
<p>爲了處理這些眞實的字符, 我們需要一個UTF8解碼器. unicode/utf8 包提供了實現, 我們可以這樣使用:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-built_in">len</span>(s); {
|
||||
r, size := utf8.DecodeRuneInString(s[i:])
|
||||
fmt.Printf(<span class="hljs-string">"%d\t%c\n"</span>, i, r)
|
||||
i += size
|
||||
}
|
||||
</code></pre>
|
||||
<p>每一次調用 DecodeRuneInString 函數都返迴一個 r 和 長度, r 對應字符本身, 長度對應r采用UTF8編碼後的字節數目. 長度可以用於更新第i個字符在字符串中的字節索引位置. 但是這種方式是笨拙的, 我們需要更簡潔的語法. 幸運的是, Go的range循環在處理字符串的時候, 會自動隱式解碼UTF8字符串. 下面的循環運行如圖3.5所示; 需要註意的是對於非ASCII, 索引更新的步長超過1個字節.</p>
|
||||
<p><img src="../images/ch3-05.png" alt=""></p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">for</span> i, r := <span class="hljs-keyword">range</span> <span class="hljs-string">"Hello, 世界"</span> {
|
||||
fmt.Printf(<span class="hljs-string">"%d\t%q\t%d\n"</span>, i, r, r)
|
||||
}
|
||||
</code></pre>
|
||||
<p>我們可以使用一個簡單的循環來統計字符串中字符的數目, 像這樣:</p>
|
||||
<pre><code class="lang-Go">n := <span class="hljs-number">0</span>
|
||||
<span class="hljs-keyword">for</span> _, _ = <span class="hljs-keyword">range</span> s {
|
||||
n++
|
||||
}
|
||||
</code></pre>
|
||||
<p>想其它形式的循環那樣, 我們可以忽略不需要的變量:</p>
|
||||
<pre><code class="lang-Go">n := <span class="hljs-number">0</span>
|
||||
<span class="hljs-keyword">for</span> <span class="hljs-keyword">range</span> s {
|
||||
n++
|
||||
}
|
||||
</code></pre>
|
||||
<p>或者我們可以直接調用 utf8.RuneCountInString(s) 函數.</p>
|
||||
<p>正如我們前面提到了, 文本字符串采用UTF8編碼隻是一種慣例,但是對於循環的眞正字符串併不是一個慣例, 這是正確的. 如果用於循環的字符串隻是一個普通的二進製數據, 或者是含有錯誤編碼的UTF8數據, 將會發送什麽?</p>
|
||||
<p>每一個UTF8字符解碼, 不管是顯示地調用 utf8.DecodeRuneInString 解碼或在 range 循環中隱式地解碼, 如果遇到一個錯誤的輸入字節, 將生成一個特别的Unicode字符 '\uFFFD', 在印刷中這個符號通常是一個黑色六角或鑽石形狀, 里面包含一個白色的問號(?). 當程序遇到這樣的一個字符, 通常是一個信號, 説明輸入併不是一個完美沒有錯誤的的UTF8編碼字符串.</p>
|
||||
<p>UTF8作爲交換格式是非常方便的, 但是在程序內部采用rune類型可能更方便, 因爲rune大小一致, 支持數組索引和方便切割.</p>
|
||||
<p>string 接受到 []rune 的轉換, 可以將一個UTF8編碼的字符串解碼爲Unicode字符序列:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-comment">// "program" in Japanese katakana</span>
|
||||
s := <span class="hljs-string">"プログラム"</span>
|
||||
fmt.Printf(<span class="hljs-string">"% x\n"</span>, s) <span class="hljs-comment">// "e3 83 97 e3 83 ad e3 82 b0 e3 83 a9 e3 83 a0"</span>
|
||||
r := []<span class="hljs-typename">rune</span>(s)
|
||||
fmt.Printf(<span class="hljs-string">"%x\n"</span>, r) <span class="hljs-comment">// "[30d7 30ed 30b0 30e9 30e0]"</span>
|
||||
</code></pre>
|
||||
<p>(在第一個Printf中的 <code>% x</code> 參數用於在每個十六進製數字前插入一個空格.)</p>
|
||||
<p>如果是將一個 []rune 類型的Unicode字符切片或數組轉爲string, 則對它們進行UTF8編碼:</p>
|
||||
<pre><code class="lang-Go">fmt.Println(<span class="hljs-typename">string</span>(r)) <span class="hljs-comment">// "プログラム"</span>
|
||||
</code></pre>
|
||||
<p>將一個整數轉型爲字符串意思是生成整數作爲Unicode碼點的UTF8編碼的字符串: </p>
|
||||
<pre><code class="lang-Go">fmt.Println(<span class="hljs-typename">string</span>(<span class="hljs-number">65</span>)) <span class="hljs-comment">// "A", not "65"</span>
|
||||
fmt.Println(<span class="hljs-typename">string</span>(<span class="hljs-number">0x4eac</span>)) <span class="hljs-comment">// "京"</span>
|
||||
</code></pre>
|
||||
<p>如果對應碼點的字符是無效的, 則用'\uFFFD'無效字符作爲替換:</p>
|
||||
<pre><code class="lang-Go">fmt.Println(<span class="hljs-typename">string</span>(<span class="hljs-number">1234567</span>)) <span class="hljs-comment">// "(?)"</span>
|
||||
</code></pre>
|
||||
<h3 id="354-字符串和byte切片">3.5.4. 字符串和Byte切片</h3>
|
||||
<p>標準庫中有四個包對字符串處理尤爲重要: bytes, strings, strconv, 和 unicode. strings 包提供了許多如字符串的査詢, 替換, 比較, 截斷, 拆分, 和合併等功能.</p>
|
||||
<p>bytes 包也提供了很多類似功能的函數, 但是針對和字符串有着相同結構的 []byte 類型. 因爲字符串是隻讀的, 因此逐步構建字符串會導致很多分配和複製. 在這種情況下, 使用 bytes.Buffer 類型會更有效, 稍後我們將展示.</p>
|
||||
<p>strconv 包提供了 布爾型, 整型數, 浮點數和對應字符串間的相互轉換, 還提供了雙引號的字符串面值形式的轉換.</p>
|
||||
<p>unicode 包提供了類似 IsDigit, IsLetter, IsUpper, 和 IsLower 等功能, 它們用於給字符分類. 每個函數有一個單一的rune類型的參數, 然後返迴一個布爾值. 像 ToUpper 和 ToLower 之類的轉換函數將用於rune字符的大小寫轉換. 所有的這些函數都是遵循Unicode標準定義的字母,數字等分類規范. strings 包也有類似的函數, 它們是 ToUpper 和 ToLower, 將原始字符串的每個字符都做相應的轉換, 然後返迴新的字符串.</p>
|
||||
<p>下面的 basename 函數的靈感由Unix shell的同名工具而來. 在我們實現的版本中, basename(s) 將看起來像是繫統路徑的前綴刪除, 同時將看似文件類型的後綴名刪除:</p>
|
||||
<pre><code class="lang-Go">fmt.Println(basename(<span class="hljs-string">"a/b/c.go"</span>)) <span class="hljs-comment">// "c"</span>
|
||||
fmt.Println(basename(<span class="hljs-string">"c.d.go"</span>)) <span class="hljs-comment">// "c.d"</span>
|
||||
fmt.Println(basename(<span class="hljs-string">"abc"</span>)) <span class="hljs-comment">// "abc"</span>
|
||||
</code></pre>
|
||||
<p>第一個版本併沒有使用任何庫, 全部手工實現:</p>
|
||||
<pre><code class="lang-Go">gopl.io/ch3/basename1
|
||||
<span class="hljs-comment">// basename removes directory components and a .suffix.</span>
|
||||
<span class="hljs-comment">// e.g., a => a, a.go => a, a/b/c.go => c, a/b.c.go => b.c</span>
|
||||
<span class="hljs-keyword">func</span> basename(s <span class="hljs-typename">string</span>) <span class="hljs-typename">string</span> {
|
||||
<span class="hljs-comment">// Discard last '/' and everything before.</span>
|
||||
<span class="hljs-keyword">for</span> i := <span class="hljs-built_in">len</span>(s) - <span class="hljs-number">1</span>; i >= <span class="hljs-number">0</span>; i-- {
|
||||
<span class="hljs-keyword">if</span> s[i] == <span class="hljs-string">'/'</span> {
|
||||
s = s[i+<span class="hljs-number">1</span>:]
|
||||
<span class="hljs-keyword">break</span>
|
||||
}
|
||||
}
|
||||
<span class="hljs-comment">// Preserve everything before last '.'.</span>
|
||||
<span class="hljs-keyword">for</span> i := <span class="hljs-built_in">len</span>(s) - <span class="hljs-number">1</span>; i >= <span class="hljs-number">0</span>; i-- {
|
||||
<span class="hljs-keyword">if</span> s[i] == <span class="hljs-string">'.'</span> {
|
||||
s = s[:i]
|
||||
<span class="hljs-keyword">break</span>
|
||||
}
|
||||
}
|
||||
<span class="hljs-keyword">return</span> s
|
||||
}
|
||||
</code></pre>
|
||||
<p>一個簡化的版本使用了 strings.LastIndex 庫函數:</p>
|
||||
<pre><code class="lang-Go">gopl.io/ch3/basename2
|
||||
|
||||
<span class="hljs-keyword">func</span> basename(s <span class="hljs-typename">string</span>) <span class="hljs-typename">string</span> {
|
||||
slash := strings.LastIndex(s, <span class="hljs-string">"/"</span>) <span class="hljs-comment">// -1 if "/" not found</span>
|
||||
s = s[slash+<span class="hljs-number">1</span>:]
|
||||
<span class="hljs-keyword">if</span> dot := strings.LastIndex(s, <span class="hljs-string">"."</span>); dot >= <span class="hljs-number">0</span> {
|
||||
s = s[:dot]
|
||||
}
|
||||
<span class="hljs-keyword">return</span> s
|
||||
}
|
||||
</code></pre>
|
||||
<p>path 和 path/filepath 包提供了關於文件名更一般的函數操作. 使用斜槓分隔路徑可以在任何操作繫統上工作. 斜槓本身不應該用於文件名, 但是在其他一些領域可能是有效的, 例如URL路徑組件. 相比之下, path/filepath 包使用操作繫統本身的路徑規則, 例如 POSIX 繫統使用 /foo/bar, Microsoft Windows 使用 c:\foo\bar 等.</p>
|
||||
<p>讓我們繼續另一個字符串的例子. 任務是將一個表示整值的字符串, 每隔三個字符插入一個逗號, 例如 "12345" 處理後成爲 "12,345". 這個版本隻適用於整數類型; 支持浮點數類型的支持留做練習.</p>
|
||||
<pre><code class="lang-Go">gopl.io/ch3/comma
|
||||
|
||||
<span class="hljs-comment">// comma inserts commas in a non-negative decimal integer string.</span>
|
||||
<span class="hljs-keyword">func</span> comma(s <span class="hljs-typename">string</span>) <span class="hljs-typename">string</span> {
|
||||
n := <span class="hljs-built_in">len</span>(s)
|
||||
<span class="hljs-keyword">if</span> n <= <span class="hljs-number">3</span> {
|
||||
<span class="hljs-keyword">return</span> s
|
||||
}
|
||||
<span class="hljs-keyword">return</span> comma(s[:n-<span class="hljs-number">3</span>]) + <span class="hljs-string">","</span> + s[n-<span class="hljs-number">3</span>:]
|
||||
}
|
||||
</code></pre>
|
||||
<p>輸入 comma 的參數是一個字符串. 如果輸入字符串的長度小於或等於3的話, 則不需要插入逗號. 否則, comma 將在最後三個字符前切割爲兩個兩個子串, 然後用前面的子串遞歸調用自身.</p>
|
||||
<p>一個字符串包含的字節數組, 一旦創建, 是不可變的. 相比之下, 一個字節切片的原始則可以自由地脩改.</p>
|
||||
<p>字符串和字節切片可以相互轉換:</p>
|
||||
<pre><code class="lang-Go">s := <span class="hljs-string">"abc"</span>
|
||||
b := []<span class="hljs-typename">byte</span>(s)
|
||||
s2 := <span class="hljs-typename">string</span>(b)
|
||||
</code></pre>
|
||||
<p>從概念上講, []byte(s) 轉換是分配了一個新的字節數組保存了字符串數據的拷貝, 然後引用這個字節數組. 編譯器的優化可以避免在一些場景下分配和複製字符串數據, 但總的來説需要確保在b被脩改的情況下, 原始的s字符串也不會改變. 將一個字節切片轉到字符串的 string(b) 操作則是構造一個拷貝, 以確保s2字符串是隻讀的.</p>
|
||||
<p>爲了避免轉換中不必要的內存分配, bytes包和strings同時提供了許多類似的實用函數. 下面是strings包中的六個函數:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">func</span> Contains(s, substr <span class="hljs-typename">string</span>) <span class="hljs-typename">bool</span>
|
||||
<span class="hljs-keyword">func</span> Count(s, sep <span class="hljs-typename">string</span>) <span class="hljs-typename">int</span>
|
||||
<span class="hljs-keyword">func</span> Fields(s <span class="hljs-typename">string</span>) []<span class="hljs-typename">string</span>
|
||||
<span class="hljs-keyword">func</span> HasPrefix(s, prefix <span class="hljs-typename">string</span>) <span class="hljs-typename">bool</span>
|
||||
<span class="hljs-keyword">func</span> Index(s, sep <span class="hljs-typename">string</span>) <span class="hljs-typename">int</span>
|
||||
<span class="hljs-keyword">func</span> Join(a []<span class="hljs-typename">string</span>, sep <span class="hljs-typename">string</span>) <span class="hljs-typename">string</span>
|
||||
</code></pre>
|
||||
<p>bytes 包中對應的六個函數:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">func</span> Contains(b, subslice []<span class="hljs-typename">byte</span>) <span class="hljs-typename">bool</span>
|
||||
<span class="hljs-keyword">func</span> Count(s, sep []<span class="hljs-typename">byte</span>) <span class="hljs-typename">int</span>
|
||||
<span class="hljs-keyword">func</span> Fields(s []<span class="hljs-typename">byte</span>) [][]<span class="hljs-typename">byte</span>
|
||||
<span class="hljs-keyword">func</span> HasPrefix(s, prefix []<span class="hljs-typename">byte</span>) <span class="hljs-typename">bool</span>
|
||||
<span class="hljs-keyword">func</span> Index(s, sep []<span class="hljs-typename">byte</span>) <span class="hljs-typename">int</span>
|
||||
<span class="hljs-keyword">func</span> Join(s [][]<span class="hljs-typename">byte</span>, sep []<span class="hljs-typename">byte</span>) []<span class="hljs-typename">byte</span>
|
||||
</code></pre>
|
||||
<p>唯一的區别是字符串類型參數被替換成了字節切片類型的參數.</p>
|
||||
<p>bytes 包還提供了 Buffer 類型用於字節切片的緩存. 一個 Buffer 開始是空的, 但是隨着 string, byte, 和 []byte 等類型數據的寫入可以動態增長, 一個 bytes.Buffer 變量併不需要處理化, 因此零值也是有效的:</p>
|
||||
<pre><code class="lang-Go">gopl.io/ch3/printints
|
||||
|
||||
<span class="hljs-comment">// intsToString is like fmt.Sprintf(values) but adds commas.</span>
|
||||
<span class="hljs-keyword">func</span> intsToString(values []<span class="hljs-typename">int</span>) <span class="hljs-typename">string</span> {
|
||||
<span class="hljs-keyword">var</span> buf bytes.Buffer
|
||||
buf.WriteByte(<span class="hljs-string">'['</span>)
|
||||
<span class="hljs-keyword">for</span> i, v := <span class="hljs-keyword">range</span> values {
|
||||
<span class="hljs-keyword">if</span> i > <span class="hljs-number">0</span> {
|
||||
buf.WriteString(<span class="hljs-string">", "</span>)
|
||||
}
|
||||
fmt.Fprintf(&buf, <span class="hljs-string">"%d"</span>, v)
|
||||
}
|
||||
buf.WriteByte(<span class="hljs-string">']'</span>)
|
||||
<span class="hljs-keyword">return</span> buf.String()
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">func</span> main() {
|
||||
fmt.Println(intsToString([]<span class="hljs-typename">int</span>{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>})) <span class="hljs-comment">// "[1, 2, 3]"</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>當向 bytes.Buffer 添加任意字符的UTF8編碼, 最好使用 bytes.Buffer 的 WriteRune 方法, 但是 WriteByte 方法對於寫入類似 '[' 和 ']' 等 ASCII 字符則更有效.</p>
|
||||
<p>bytes.Buffer 類型有着諸多實用的功能, 我們在第七章討論接口時層涉及到, 我們將看看如何將它用作一個I/O 的輸入和輸齣對象, 例如 Fprintf 的 io.Writer 輸齣, 或作爲輸入源 io.Reader.</p>
|
||||
<p><strong>練習3.10:</strong> 編寫一個非遞歸版本的comma函數, 使用 bytes.Buffer 代替字符串鏈接操作.</p>
|
||||
<p><strong>練習3.11:</strong> 完善 comma 函數, 以支持浮點數處理和一個可選的正負號處理.</p>
|
||||
<p><strong>練習3.12:</strong> 編寫一個函數, 判斷兩個字符串是否是是相互打亂的, 也就是説它們有着相同的字符, 但是對應不同的順序.</p>
|
||||
<h3 id="355-字符串和數字的轉換">3.5.5. 字符串和數字的轉換</h3>
|
||||
<p>除了字符串, 字符, 字節 之間的轉換, 字符串和數值之間的轉換也比較常見. 由 strconv 包提供這類轉換功能.</p>
|
||||
<p>將一個整數轉爲字符串, 一種方法是用 fmt.Sprintf; 另一個方法是用 strconv.Itoa(“整數到ASCII”):</p>
|
||||
<pre><code class="lang-Go">x := <span class="hljs-number">123</span>
|
||||
y := fmt.Sprintf(<span class="hljs-string">"%d"</span>, x)
|
||||
fmt.Println(y, strconv.Itoa(x)) <span class="hljs-comment">// "123 123"</span>
|
||||
</code></pre>
|
||||
<p>FormatInt和FormatUint可以用不同的進製來格式化數字:</p>
|
||||
<pre><code class="lang-Go">fmt.Println(strconv.FormatInt(<span class="hljs-typename">int64</span>(x), <span class="hljs-number">2</span>)) <span class="hljs-comment">// "1111011"</span>
|
||||
</code></pre>
|
||||
<p>fmt.Printf 函數的 %b, %d, %u, 和 %x 等參數提供功能往往比strconv 包的 Format 函數方便很多, 特别是在需要包含附加信息的時候:</p>
|
||||
<pre><code class="lang-Go">s := fmt.Sprintf(<span class="hljs-string">"x=%b"</span>, x) <span class="hljs-comment">// "x=1111011"</span>
|
||||
</code></pre>
|
||||
<p>如果要將一個字符串解析爲整數, 可以使用 strconv 包的 Atoi 或 ParseInt 函數, 還有用於解析無符號整數的 ParseUint 函數:</p>
|
||||
<pre><code class="lang-Go">x, err := strconv.Atoi(<span class="hljs-string">"123"</span>) <span class="hljs-comment">// x is an int</span>
|
||||
y, err := strconv.ParseInt(<span class="hljs-string">"123"</span>, <span class="hljs-number">10</span>, <span class="hljs-number">64</span>) <span class="hljs-comment">// base 10, up to 64 bits</span>
|
||||
</code></pre>
|
||||
<p>ParseInt 函數的第三個參數是用於指定整型數的大小; 例如16表示int16, 0則表示int. 在任何情況下, 返迴的結果 y 總是 int64 類型, 你可以通過強製類型轉換將它轉爲更小的整數類型.</p>
|
||||
<p>有時候也會使用 fmt.Scanf 來解析輸入的字符串和數字, 特别是當字符串和數字混合在一行的時候, 它可以靈活處理不完整或不規則的輸入.</p>
|
||||
|
||||
|
||||
</section>
|
||||
@@ -2071,7 +2320,7 @@
|
||||
</div>
|
||||
|
||||
|
||||
<a href="../ch3/ch3-04.html" class="navigation navigation-prev " aria-label="Previous page: 佈爾型"><i class="fa fa-angle-left"></i></a>
|
||||
<a href="../ch3/ch3-04.html" class="navigation navigation-prev " aria-label="Previous page: 布爾型"><i class="fa fa-angle-left"></i></a>
|
||||
|
||||
|
||||
<a href="../ch3/ch3-06.html" class="navigation navigation-next " aria-label="Next page: 常量"><i class="fa fa-angle-right"></i></a>
|
||||
|
||||
259
ch3/ch3-06.html
259
ch3/ch3-06.html
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="3.6" data-chapter-title="常量" data-filepath="ch3/ch3-06.md" data-basepath=".." data-revision="Wed Dec 16 2015 10:54:29 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="3.6" data-chapter-title="常量" data-filepath="ch3/ch3-06.md" data-basepath=".." data-revision="Mon Dec 21 2015 12:51:02 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
<b>0.5.</b>
|
||||
|
||||
緻謝
|
||||
致謝
|
||||
</a>
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
|
||||
<b>1.3.</b>
|
||||
|
||||
査找重復的行
|
||||
査找重複的行
|
||||
</a>
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
|
||||
<b>1.4.</b>
|
||||
|
||||
GIF動畫
|
||||
GIF動畵
|
||||
</a>
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
<b>1.6.</b>
|
||||
|
||||
併髮穫取多個URL
|
||||
併發穫取多個URL
|
||||
</a>
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
|
||||
<b>3.3.</b>
|
||||
|
||||
復數
|
||||
複數
|
||||
</a>
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@
|
||||
|
||||
<b>3.4.</b>
|
||||
|
||||
佈爾型
|
||||
布爾型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@
|
||||
|
||||
<b>4.</b>
|
||||
|
||||
復閤數據類型
|
||||
複合數據類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@
|
||||
|
||||
<b>6.2.</b>
|
||||
|
||||
基於指鍼對象的方法
|
||||
基於指針對象的方法
|
||||
</a>
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
|
||||
<b>6.4.</b>
|
||||
|
||||
方法值和方法錶達式
|
||||
方法值和方法表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -953,7 +953,7 @@
|
||||
|
||||
<b>7.1.</b>
|
||||
|
||||
接口是閤約
|
||||
接口是合約
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1073,7 +1073,7 @@
|
||||
|
||||
<b>7.9.</b>
|
||||
|
||||
示例: 錶達式求值
|
||||
示例: 表達式求值
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1103,7 +1103,7 @@
|
||||
|
||||
<b>7.11.</b>
|
||||
|
||||
基於類型斷言識彆錯誤類型
|
||||
基於類型斷言識别錯誤類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1214,7 +1214,7 @@
|
||||
|
||||
<b>8.2.</b>
|
||||
|
||||
示例: 併髮的Clock服務
|
||||
示例: 併發的Clock服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1229,7 +1229,7 @@
|
||||
|
||||
<b>8.3.</b>
|
||||
|
||||
示例: 併髮的Echo服務
|
||||
示例: 併發的Echo服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1274,7 +1274,7 @@
|
||||
|
||||
<b>8.6.</b>
|
||||
|
||||
示例: 併髮的Web爬蟲
|
||||
示例: 併發的Web爬蟲
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1289,7 +1289,7 @@
|
||||
|
||||
<b>8.7.</b>
|
||||
|
||||
基於select的多路復用
|
||||
基於select的多路複用
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1304,7 +1304,7 @@
|
||||
|
||||
<b>8.8.</b>
|
||||
|
||||
示例: 併髮的字典遍歷
|
||||
示例: 併發的字典遍歷
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1319,7 +1319,7 @@
|
||||
|
||||
<b>8.9.</b>
|
||||
|
||||
併髮的退齣
|
||||
併發的退齣
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1354,7 +1354,7 @@
|
||||
|
||||
<b>9.</b>
|
||||
|
||||
基於共享變量的併髮
|
||||
基於共享變量的併發
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1415,7 +1415,7 @@
|
||||
|
||||
<b>9.4.</b>
|
||||
|
||||
內存衕步
|
||||
內存同步
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1460,7 +1460,7 @@
|
||||
|
||||
<b>9.7.</b>
|
||||
|
||||
示例: 併髮的非阻塞緩存
|
||||
示例: 併發的非阻塞緩存
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1475,7 +1475,7 @@
|
||||
|
||||
<b>9.8.</b>
|
||||
|
||||
Goroutines和綫程
|
||||
Goroutines和線程
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1748,7 +1748,7 @@
|
||||
|
||||
<b>12.1.</b>
|
||||
|
||||
為何需要反射?
|
||||
爲何需要反射?
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1793,7 +1793,7 @@
|
||||
|
||||
<b>12.4.</b>
|
||||
|
||||
示例: 編碼S錶達式
|
||||
示例: 編碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1823,7 +1823,7 @@
|
||||
|
||||
<b>12.6.</b>
|
||||
|
||||
示例: 解碼S錶達式
|
||||
示例: 解碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1975,50 +1975,14 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="14" data-path="exercise/ex.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.</b>
|
||||
|
||||
習題解答
|
||||
</a>
|
||||
|
||||
|
||||
<ul class="articles">
|
||||
|
||||
|
||||
<li class="chapter " data-level="14.1" data-path="exercise/ex-ch1.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex-ch1.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.1.</b>
|
||||
|
||||
第一章 入門
|
||||
</a>
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="15" data-path="errata.html">
|
||||
<li class="chapter " data-level="14" data-path="errata.html">
|
||||
|
||||
|
||||
<a href="../errata.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>15.</b>
|
||||
<b>14.</b>
|
||||
|
||||
勘誤
|
||||
</a>
|
||||
@@ -2060,7 +2024,170 @@
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h2 id="36-常量">3.6. 常量</h2>
|
||||
<p>TODO</p>
|
||||
<p>常量表達式的值在編譯期計算, 而不是在運行期. 每種常量的潛在類型都是基礎類型: boolean, string, 或數字.</p>
|
||||
<p>一個常量的聲明語句定義了常量的名字, 和變量的聲明語法類似, 常量的值不可脩改, 這樣可以防止在運行期被意外或惡意的脩改. 例如, 常量比變量更適合用於表達像 π 之類的數學常數, 因爲它們的值不會變化:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> pi = <span class="hljs-number">3.14159</span> <span class="hljs-comment">// approximately; math.Pi is a better approximation</span>
|
||||
</code></pre>
|
||||
<p>和變量聲明一樣, 可以批量聲明多個常量; 這比較適合聲明一組相關的常量:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> (
|
||||
e = <span class="hljs-number">2.71828182845904523536028747135266249775724709369995957496696763</span>
|
||||
pi = <span class="hljs-number">3.14159265358979323846264338327950288419716939937510582097494459</span>
|
||||
)
|
||||
</code></pre>
|
||||
<p>許多常量的運算可以在編譯期完成, 這樣可以減少運行時的工作, 也方便其他編譯優化. 當操作數是常量時, 一些運行時的錯誤可以在編譯時發現, 例如整數除零, 字符串索引越界, 任何導致無效浮點數的操作等.</p>
|
||||
<p>常量間的所有算術運算, 邏輯運算和比較運算的結果也是常量, 對常量的類型轉換操作或以下函數調用都是返迴常量結果: len, cap, real, imag, complex, 和 unsafe.Sizeof(§13.1).</p>
|
||||
<p>因爲它們的值是在編譯期就確定的, 因此常量可以是構成類型的一部分, 例如用於指定數組類型的長度:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> IPv4Len = <span class="hljs-number">4</span>
|
||||
|
||||
<span class="hljs-comment">// parseIPv4 parses an IPv4 address (d.d.d.d).</span>
|
||||
<span class="hljs-keyword">func</span> parseIPv4(s <span class="hljs-typename">string</span>) IP {
|
||||
<span class="hljs-keyword">var</span> p [IPv4Len]<span class="hljs-typename">byte</span>
|
||||
<span class="hljs-comment">// ...</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>一個常量的聲明也可以包含一個類型和一個值, 但是如果沒有顯式指明類型, 那麽將從右邊的表達式推斷類型. 在下面的代碼中, time.Duration 是一個命名類型, 底層類型是 int64, time.Minute 是對應類型的常量. 下面聲明的兩個常量都是 time.Duration 類型, 可以通過 %T 參數打印類型信息:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> noDelay time.Duration = <span class="hljs-number">0</span>
|
||||
<span class="hljs-keyword">const</span> timeout = <span class="hljs-number">5</span> * time.Minute
|
||||
fmt.Printf(<span class="hljs-string">"%T %[1]v\n"</span>, noDelay) <span class="hljs-comment">// "time.Duration 0"</span>
|
||||
fmt.Printf(<span class="hljs-string">"%T %[1]v\n"</span>, timeout) <span class="hljs-comment">// "time.Duration 5m0s</span>
|
||||
fmt.Printf(<span class="hljs-string">"%T %[1]v\n"</span>, time.Minute) <span class="hljs-comment">// "time.Duration 1m0s"</span>
|
||||
</code></pre>
|
||||
<p>如果是批量聲明的常量, 除了第一個外其他常量的右邊的表發生可以省略, 如果省略則表示使用前面的表達式, 對應的常量類型也一樣. 例如:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> (
|
||||
a = <span class="hljs-number">1</span>
|
||||
b
|
||||
c = <span class="hljs-number">2</span>
|
||||
d
|
||||
)
|
||||
|
||||
fmt.Println(a, b, c, d) <span class="hljs-comment">// "1 1 2 2"</span>
|
||||
</code></pre>
|
||||
<p>如果隻是簡單地複製右邊的常量表達式, 併沒有太實用的價值. 但是它可以帶來其他的特性, 那就是 iota 常量生成器.</p>
|
||||
<h3 id="361-iota-常量生成器">3.6.1. iota 常量生成器</h3>
|
||||
<p>常量聲明可以使用 iota 常量生成器, 用於生成一組相似的常量值, 但是不用每行都寫一遍. 在一個 const 聲明語句中, 在開始一行 iota 將會被置爲0, 然後在每一個有常量聲明的行加一.</p>
|
||||
<p>下面是來自 time 包的例子, 它首先定義了Weekday命名類型, 然後爲一週的每天定義一個常量, 從週日0開始. 這種類型一般被稱爲枚舉類型.</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">type</span> Weekday <span class="hljs-typename">int</span>
|
||||
|
||||
<span class="hljs-keyword">const</span> (
|
||||
Sunday Weekday = <span class="hljs-constant">iota</span>
|
||||
Monday
|
||||
Tuesday
|
||||
Wednesday
|
||||
Thursday
|
||||
Friday
|
||||
Saturday
|
||||
)
|
||||
</code></pre>
|
||||
<p>週一將對應0, 週一爲1, 如此等等.</p>
|
||||
<p>我們也可以在複雜的常量表達式中使用 iota, 下面是來自 net 包的例子, 用於給一個無符號整數的最低5bit的每個bit給定一個名字:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">type</span> Flags <span class="hljs-typename">uint</span>
|
||||
|
||||
<span class="hljs-keyword">const</span> (
|
||||
FlagUp Flags = <span class="hljs-number">1</span> << <span class="hljs-constant">iota</span> <span class="hljs-comment">// is up</span>
|
||||
FlagBroadcast <span class="hljs-comment">// supports broadcast access capability</span>
|
||||
FlagLoopback <span class="hljs-comment">// is a loopback interface</span>
|
||||
FlagPointToPoint <span class="hljs-comment">// belongs to a point-to-point link</span>
|
||||
FlagMulticast <span class="hljs-comment">// supports multicast access capability</span>
|
||||
)
|
||||
</code></pre>
|
||||
<p>隨着 iota 的遞增, 每個常量對應表達式 1 << iota, 是連續的2的冪, 分别對應一個bit位置. 使用這些常量可以測試, 設置, 或清除對應的bit位的值:</p>
|
||||
<pre><code class="lang-Go">gopl.io/ch3/netflag
|
||||
|
||||
<span class="hljs-keyword">func</span> IsUp(v Flags) <span class="hljs-typename">bool</span> { <span class="hljs-keyword">return</span> v&FlagUp == FlagUp }
|
||||
<span class="hljs-keyword">func</span> TurnDown(v *Flags) { *v &^= FlagUp }
|
||||
<span class="hljs-keyword">func</span> SetBroadcast(v *Flags) { *v |= FlagBroadcast }
|
||||
<span class="hljs-keyword">func</span> IsCast(v Flags) <span class="hljs-typename">bool</span> { <span class="hljs-keyword">return</span> v&(FlagBroadcast|FlagMulticast) != <span class="hljs-number">0</span> }
|
||||
|
||||
unc main() {
|
||||
<span class="hljs-keyword">var</span> v Flags = FlagMulticast | FlagUp
|
||||
fmt.Printf(<span class="hljs-string">"%b %t\n"</span>, v, IsUp(v)) <span class="hljs-comment">// "10001 true"</span>
|
||||
TurnDown(&v)
|
||||
fmt.Printf(<span class="hljs-string">"%b %t\n"</span>, v, IsUp(v)) <span class="hljs-comment">// "10000 false"</span>
|
||||
SetBroadcast(&v)
|
||||
fmt.Printf(<span class="hljs-string">"%b %t\n"</span>, v, IsUp(v)) <span class="hljs-comment">// "10010 false"</span>
|
||||
fmt.Printf(<span class="hljs-string">"%b %t\n"</span>, v, IsCast(v)) <span class="hljs-comment">// "10010 true"</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>下面是一個更複雜的例子, 每個常量都是1024的冪:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> (
|
||||
_ = <span class="hljs-number">1</span> << (<span class="hljs-number">10</span> * <span class="hljs-constant">iota</span>)
|
||||
KiB <span class="hljs-comment">// 1024</span>
|
||||
MiB <span class="hljs-comment">// 1048576</span>
|
||||
GiB <span class="hljs-comment">// 1073741824</span>
|
||||
TiB <span class="hljs-comment">// 1099511627776 (exceeds 1 << 32)</span>
|
||||
PiB <span class="hljs-comment">// 1125899906842624</span>
|
||||
EiB <span class="hljs-comment">// 1152921504606846976</span>
|
||||
ZiB <span class="hljs-comment">// 1180591620717411303424 (exceeds 1 << 64)</span>
|
||||
YiB <span class="hljs-comment">// 1208925819614629174706176</span>
|
||||
)
|
||||
</code></pre>
|
||||
<p>iota 機製也有其局限性. 例如, 它併不能用於産生1000的冪(KB,MB,等等), 因爲併沒有計算冪的運算符.</p>
|
||||
<p><strong>練習3.13:</strong> 編寫KB,MB的常量聲明, 然後擴展到YB.</p>
|
||||
<h3 id="362-無類型常量">3.6.2. 無類型常量</h3>
|
||||
<p>Go語言的常量有點不尋常. 雖然一個常量可以有任意有一個確定的基礎類型, 例如 int 或 float64, 或者是類似 time.Duration 這樣命名的基礎類型, 但是許多常量併沒有一個明確的基礎類型. 編譯期爲這些沒有明確的基礎類型的數字常量提供比基礎類型或機器更高精度的算術運算; 你可以認爲至少有256bit的運算精度. 這里有六種未明確類型的常量類型, 分别是 無類型的布爾型, 無類型的整數, 無類型的字符, 無類型的浮點數, 無類型的複數, 無類型的字符串.</p>
|
||||
<p>通過延遲明確具體類型, 無類型的常量不僅可以提供更高的精度, 而且可以直接用於更多的表達式而不需要類型轉換. 例如 例子中的 ZiB 和 YiB 的值已經超齣任何Go中整數類型能表達的范圍, 但是它們依然是合法的常量, 而且可以像下面表達式這樣使用:</p>
|
||||
<pre><code class="lang-Go">fmt.Println(YiB/ZiB) <span class="hljs-comment">// "1024"</span>
|
||||
</code></pre>
|
||||
<p>另一個例子, math.Pi 無類型的浮點數常量, 可以直接用於任意需要浮點數或複數的地方:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> x <span class="hljs-typename">float32</span> = math.Pi
|
||||
<span class="hljs-keyword">var</span> y <span class="hljs-typename">float64</span> = math.Pi
|
||||
<span class="hljs-keyword">var</span> z <span class="hljs-typename">complex128</span> = math.Pi
|
||||
</code></pre>
|
||||
<p>如果 math.Pi 被確定爲特定類型, 比如 float64, 那麽結果精度可能會不一樣, 同時對於需要float32或complex128類型值的地方會需要一個明確的類型轉換:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> Pi64 <span class="hljs-typename">float64</span> = math.Pi
|
||||
|
||||
<span class="hljs-keyword">var</span> x <span class="hljs-typename">float32</span> = <span class="hljs-typename">float32</span>(Pi64)
|
||||
<span class="hljs-keyword">var</span> y <span class="hljs-typename">float64</span> = Pi64
|
||||
<span class="hljs-keyword">var</span> z <span class="hljs-typename">complex128</span> = <span class="hljs-typename">complex128</span>(Pi64)
|
||||
</code></pre>
|
||||
<p>對於常量面值, 不同的寫法對應不同的類型. 例如 0, 0.0, 0i, 和 '\u0000' 雖然有着相同的常量值, 但是它們分别對應無類型的整數,無類型的浮點數,無類型的複數,和無類型的字符等不同的常量類型. 同樣, true 和 false 也是無類型的布爾類型, 字符串面值常量是無類型的字符串.</p>
|
||||
<p>前面説過除法運算符 / 根據操作數的類型生成對應類型的結果. 因此, 不同寫法的常量除法表達式可能對應不同的結果:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> f <span class="hljs-typename">float64</span> = <span class="hljs-number">212</span>
|
||||
fmt.Println((f - <span class="hljs-number">32</span>) * <span class="hljs-number">5</span> / <span class="hljs-number">9</span>) <span class="hljs-comment">// "100"; (f - 32) * 5 is a float64</span>
|
||||
fmt.Println(<span class="hljs-number">5</span> / <span class="hljs-number">9</span> * (f - <span class="hljs-number">32</span>)) <span class="hljs-comment">// "0"; 5/9 is an untyped integer, 0</span>
|
||||
fmt.Println(<span class="hljs-number">5.0</span> / <span class="hljs-number">9.0</span> * (f - <span class="hljs-number">32</span>)) <span class="hljs-comment">// "100"; 5.0/9.0 is an untyped float</span>
|
||||
</code></pre>
|
||||
<p>隻有常量可以是無類型的. 當一個無類型的常量被賦值給一個變量, 就像上面的第一行語句, 或者是像其餘三個語句中右邊表達式中含有明確類型的值, 無類型的常量將會被隱式轉換爲對應的類型, 如果可能的話.</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> f <span class="hljs-typename">float64</span> = <span class="hljs-number">3</span> + <span class="hljs-number">0i</span> <span class="hljs-comment">// untyped complex -> float64</span>
|
||||
f = <span class="hljs-number">2</span> <span class="hljs-comment">// untyped integer -> float64</span>
|
||||
f = <span class="hljs-number">1e123</span> <span class="hljs-comment">// untyped floating-point -> float64</span>
|
||||
f = <span class="hljs-string">'a'</span> <span class="hljs-comment">// untyped rune -> float64</span>
|
||||
</code></pre>
|
||||
<p>上面的語句相當於:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> f <span class="hljs-typename">float64</span> = <span class="hljs-typename">float64</span>(<span class="hljs-number">3</span> + <span class="hljs-number">0i</span>)
|
||||
f = <span class="hljs-typename">float64</span>(<span class="hljs-number">2</span>)
|
||||
f = <span class="hljs-typename">float64</span>(<span class="hljs-number">1e123</span>)
|
||||
f = <span class="hljs-typename">float64</span>(<span class="hljs-string">'a'</span>)
|
||||
</code></pre>
|
||||
<p>無論是隱式或顯式, 將一種類型轉換爲另一種類型要求目標可以表示原始值. 對於浮點數和複數, 可能會有舍入處理:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">const</span> (
|
||||
deadbeef = <span class="hljs-number">0xdeadbeef</span> <span class="hljs-comment">// untyped int with value 3735928559</span>
|
||||
a = <span class="hljs-typename">uint32</span>(deadbeef) <span class="hljs-comment">// uint32 with value 3735928559</span>
|
||||
b = <span class="hljs-typename">float32</span>(deadbeef) <span class="hljs-comment">// float32 with value 3735928576 (rounded up)</span>
|
||||
c = <span class="hljs-typename">float64</span>(deadbeef) <span class="hljs-comment">// float64 with value 3735928559 (exact)</span>
|
||||
d = <span class="hljs-typename">int32</span>(deadbeef) <span class="hljs-comment">// compile error: constant overflows int32</span>
|
||||
e = <span class="hljs-typename">float64</span>(<span class="hljs-number">1e309</span>) <span class="hljs-comment">// compile error: constant overflows float64</span>
|
||||
f = <span class="hljs-typename">uint</span>(-<span class="hljs-number">1</span>) <span class="hljs-comment">// compile error: constant underflows uint</span>
|
||||
)
|
||||
</code></pre>
|
||||
<p>對於一個沒有顯式類型的變量聲明(包括短變量聲明語法), 無類型的常量會被隱式轉爲默認的變量類型, 就像下面的例子:</p>
|
||||
<pre><code class="lang-Go">i := <span class="hljs-number">0</span> <span class="hljs-comment">// untyped integer; implicit int(0)</span>
|
||||
r := <span class="hljs-string">'\000'</span> <span class="hljs-comment">// untyped rune; implicit rune('\000')</span>
|
||||
f := <span class="hljs-number">0.0</span> <span class="hljs-comment">// untyped floating-point; implicit float64(0.0)</span>
|
||||
c := <span class="hljs-number">0i</span> <span class="hljs-comment">// untyped complex; implicit complex128(0i)</span>
|
||||
</code></pre>
|
||||
<p>註意默認類型是規則的: 無類型的整數常量默認轉換爲int, 對應不確定的尺寸, 但是浮點數好複數常量則默認轉換爲float64和complex128. Go語言本身併沒有不確定的尺寸的浮點數和複數類型, 因爲如何不知道浮點數類型的話很難寫齣正確的數值算法.</p>
|
||||
<p>如果要給變量一個不同的類型, 我們必鬚顯式地將無類型的常量轉化爲所需的類型, 或給聲明的變量指定類型, 像下面例子這樣:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">var</span> i = <span class="hljs-typename">int8</span>(<span class="hljs-number">0</span>)
|
||||
<span class="hljs-keyword">var</span> i <span class="hljs-typename">int8</span> = <span class="hljs-number">0</span>
|
||||
</code></pre>
|
||||
<p>當嚐試將這些無類型的常量轉爲一個接口值時(見第7章), 這些默認類型將顯得尤爲重要, 因爲要靠它們明確接口對應的動態類型.</p>
|
||||
<pre><code class="lang-Go">fmt.Printf(<span class="hljs-string">"%T\n"</span>, <span class="hljs-number">0</span>) <span class="hljs-comment">// "int"</span>
|
||||
fmt.Printf(<span class="hljs-string">"%T\n"</span>, <span class="hljs-number">0.0</span>) <span class="hljs-comment">// "float64"</span>
|
||||
fmt.Printf(<span class="hljs-string">"%T\n"</span>, <span class="hljs-number">0i</span>) <span class="hljs-comment">// "complex128"</span>
|
||||
fmt.Printf(<span class="hljs-string">"%T\n"</span>, <span class="hljs-string">'\000'</span>) <span class="hljs-comment">// "int32" (rune)</span>
|
||||
</code></pre>
|
||||
<p>現在我們已經講述了Go語言中全部的基礎數據類型. 下一步將演示如何用基礎數據類型組合成數組或結構體等複雜數據類型, 然後構建用於解決實際編程問題的數據結構, 這將是第四章的討論主題.</p>
|
||||
|
||||
|
||||
</section>
|
||||
@@ -2074,7 +2201,7 @@
|
||||
<a href="../ch3/ch3-05.html" class="navigation navigation-prev " aria-label="Previous page: 字符串"><i class="fa fa-angle-left"></i></a>
|
||||
|
||||
|
||||
<a href="../ch4/ch4.html" class="navigation navigation-next " aria-label="Next page: 復閤數據類型"><i class="fa fa-angle-right"></i></a>
|
||||
<a href="../ch4/ch4.html" class="navigation navigation-next " aria-label="Next page: 複合數據類型"><i class="fa fa-angle-right"></i></a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
96
ch3/ch3.html
96
ch3/ch3.html
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="3" data-chapter-title="基礎數據類型" data-filepath="ch3/ch3.md" data-basepath=".." data-revision="Wed Dec 16 2015 10:54:29 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="3" data-chapter-title="基礎數據類型" data-filepath="ch3/ch3.md" data-basepath=".." data-revision="Mon Dec 21 2015 12:51:02 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
<b>0.5.</b>
|
||||
|
||||
緻謝
|
||||
致謝
|
||||
</a>
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
|
||||
<b>1.3.</b>
|
||||
|
||||
査找重復的行
|
||||
査找重複的行
|
||||
</a>
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@
|
||||
|
||||
<b>1.4.</b>
|
||||
|
||||
GIF動畫
|
||||
GIF動畵
|
||||
</a>
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@
|
||||
|
||||
<b>1.6.</b>
|
||||
|
||||
併髮穫取多個URL
|
||||
併發穫取多個URL
|
||||
</a>
|
||||
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
|
||||
<b>3.3.</b>
|
||||
|
||||
復數
|
||||
複數
|
||||
</a>
|
||||
|
||||
|
||||
@@ -494,7 +494,7 @@
|
||||
|
||||
<b>3.4.</b>
|
||||
|
||||
佈爾型
|
||||
布爾型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@
|
||||
|
||||
<b>4.</b>
|
||||
|
||||
復閤數據類型
|
||||
複合數據類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -857,7 +857,7 @@
|
||||
|
||||
<b>6.2.</b>
|
||||
|
||||
基於指鍼對象的方法
|
||||
基於指針對象的方法
|
||||
</a>
|
||||
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
|
||||
<b>6.4.</b>
|
||||
|
||||
方法值和方法錶達式
|
||||
方法值和方法表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -953,7 +953,7 @@
|
||||
|
||||
<b>7.1.</b>
|
||||
|
||||
接口是閤約
|
||||
接口是合約
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1073,7 +1073,7 @@
|
||||
|
||||
<b>7.9.</b>
|
||||
|
||||
示例: 錶達式求值
|
||||
示例: 表達式求值
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1103,7 +1103,7 @@
|
||||
|
||||
<b>7.11.</b>
|
||||
|
||||
基於類型斷言識彆錯誤類型
|
||||
基於類型斷言識别錯誤類型
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1214,7 +1214,7 @@
|
||||
|
||||
<b>8.2.</b>
|
||||
|
||||
示例: 併髮的Clock服務
|
||||
示例: 併發的Clock服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1229,7 +1229,7 @@
|
||||
|
||||
<b>8.3.</b>
|
||||
|
||||
示例: 併髮的Echo服務
|
||||
示例: 併發的Echo服務
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1274,7 +1274,7 @@
|
||||
|
||||
<b>8.6.</b>
|
||||
|
||||
示例: 併髮的Web爬蟲
|
||||
示例: 併發的Web爬蟲
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1289,7 +1289,7 @@
|
||||
|
||||
<b>8.7.</b>
|
||||
|
||||
基於select的多路復用
|
||||
基於select的多路複用
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1304,7 +1304,7 @@
|
||||
|
||||
<b>8.8.</b>
|
||||
|
||||
示例: 併髮的字典遍歷
|
||||
示例: 併發的字典遍歷
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1319,7 +1319,7 @@
|
||||
|
||||
<b>8.9.</b>
|
||||
|
||||
併髮的退齣
|
||||
併發的退齣
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1354,7 +1354,7 @@
|
||||
|
||||
<b>9.</b>
|
||||
|
||||
基於共享變量的併髮
|
||||
基於共享變量的併發
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1415,7 +1415,7 @@
|
||||
|
||||
<b>9.4.</b>
|
||||
|
||||
內存衕步
|
||||
內存同步
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1460,7 +1460,7 @@
|
||||
|
||||
<b>9.7.</b>
|
||||
|
||||
示例: 併髮的非阻塞緩存
|
||||
示例: 併發的非阻塞緩存
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1475,7 +1475,7 @@
|
||||
|
||||
<b>9.8.</b>
|
||||
|
||||
Goroutines和綫程
|
||||
Goroutines和線程
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1748,7 +1748,7 @@
|
||||
|
||||
<b>12.1.</b>
|
||||
|
||||
為何需要反射?
|
||||
爲何需要反射?
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1793,7 +1793,7 @@
|
||||
|
||||
<b>12.4.</b>
|
||||
|
||||
示例: 編碼S錶達式
|
||||
示例: 編碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1823,7 +1823,7 @@
|
||||
|
||||
<b>12.6.</b>
|
||||
|
||||
示例: 解碼S錶達式
|
||||
示例: 解碼S表達式
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1975,50 +1975,14 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="14" data-path="exercise/ex.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.</b>
|
||||
|
||||
習題解答
|
||||
</a>
|
||||
|
||||
|
||||
<ul class="articles">
|
||||
|
||||
|
||||
<li class="chapter " data-level="14.1" data-path="exercise/ex-ch1.html">
|
||||
|
||||
|
||||
<a href="../exercise/ex-ch1.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.1.</b>
|
||||
|
||||
第一章 入門
|
||||
</a>
|
||||
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="15" data-path="errata.html">
|
||||
<li class="chapter " data-level="14" data-path="errata.html">
|
||||
|
||||
|
||||
<a href="../errata.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>15.</b>
|
||||
<b>14.</b>
|
||||
|
||||
勘誤
|
||||
</a>
|
||||
@@ -2060,8 +2024,8 @@
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h1 id="第3章-基礎數據類型">第3章 基礎數據類型</h1>
|
||||
<p>雖然從底層而言,所有的數據都是比特,但計算機操作的是固定位數的數,如整數、浮點數、比特組、內存地址。將這些數,進一步組織在一起,可錶達更多的對象,如數據包、像素點、詩歌,甚至任何對象.Go提供了豐富的數據組織形式,這依賴於Go內置的數據類型。這些內置的數據類型,兼顧了硬件的特性和錶達復雜數據結構的便捷性。</p>
|
||||
<p>Go將數據類型分為四類:基礎類型、復閤類型、引用類型和接口類型。本章介紹基礎類型,包括:數字,字符串和佈爾型。復閤數據類型——數組(§4.1)和結構體(§4.2)——通過組閤簡單類型,錶達更加復雜的數據結構。引用類型包括指鍼(§2.3.2)、切片(§4.2))字典(§4.3)、函數(§5)、通道(§8).雖然種類很多,但它們都是對程序中一個變量或狀態的間接引用。這意味着對任一引用的脩改都會影響所有該引用的拷貝。我們將在第7章介紹接口類型。</p>
|
||||
<p>雖然從底層而言,所有的數據都是比特,但計算機操作的是固定位數的數,如整數、浮點數、比特組、內存地址。將這些數,進一步組織在一起,可表達更多的對象,如數據包、像素點、詩歌,甚至任何對象.Go提供了豐富的數據組織形式,這依賴於Go內置的數據類型。這些內置的數據類型,兼顧了硬件的特性和表達複雜數據結構的便捷性。</p>
|
||||
<p>Go將數據類型分爲四類:基礎類型、複合類型、引用類型和接口類型。本章介紹基礎類型,包括:數字,字符串和布爾型。複合數據類型——數組(§4.1)和結構體(§4.2)——通過組合簡單類型,表達更加複雜的數據結構。引用類型包括指針(§2.3.2)、切片(§4.2))字典(§4.3)、函數(§5)、通道(§8).雖然種類很多,但它們都是對程序中一個變量或狀態的間接引用。這意味着對任一引用的脩改都會影響所有該引用的拷貝。我們將在第7章介紹接口類型。</p>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user