mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-19 20:24:20 +08:00
rebuild
This commit is contained in:
120
ch6/ch6-01.html
120
ch6/ch6-01.html
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="6.1" data-chapter-title="方法聲明" data-filepath="ch6/ch6-01.md" data-basepath=".." data-revision="Wed Dec 16 2015 10:54:29 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="6.1" data-chapter-title="方法聲明" data-filepath="ch6/ch6-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,8 +2024,8 @@
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h2 id="61-方法聲明">6.1. 方法聲明</h2>
|
||||
<p>在函數聲明時,在其名字之前放上一個變量,卽是一個方法。這個附加的參數會將該函數附加到這種類型上,卽相當於為這種類型定義了一個獨佔的方法。</p>
|
||||
<p>下麫來寫我們第一個方法的例子,這個例子在package geometry下:</p>
|
||||
<p>在函數聲明時,在其名字之前放上一個變量,卽是一個方法。這個附加的參數會將該函數附加到這種類型上,卽相當於爲這種類型定義了一個獨占的方法。</p>
|
||||
<p>下面來寫我們第一個方法的例子,這個例子在package geometry下:</p>
|
||||
<pre><code class="lang-go">gopl.io/ch6/geometry
|
||||
<span class="hljs-keyword">package</span> geometry
|
||||
|
||||
@@ -2080,17 +2044,17 @@
|
||||
<span class="hljs-keyword">return</span> math.Hypot(q.X-p.X, q.Y-p.Y)
|
||||
}
|
||||
</code></pre>
|
||||
<p>上麫的代碼裏那個附加的參數p,叫做方法的接收器(receiver),早期的麫曏對象語言留下的遺產將調用一個方法稱為“曏一個對象髮送消息”。</p>
|
||||
<p>在Go語言中,我們併不會像其它語言那樣用this或者self作為接收器;我們可以任意的選擇接收器的名字。由於接收器的名字經常會被使用到,所以保持其在方法間傳遞時的一緻性和簡短性是不錯的主意。這裏的建議是可以使用其類型的第一個字母,比如這裏使用了Point的首字母p。</p>
|
||||
<p>在方法調用過程中,接收器參數一般會在方法名之前齣現。這和方法聲明是一樣的,都是接收器參數在方法名字之前。下麫是例子:</p>
|
||||
<p>上面的代碼里那個附加的參數p,叫做方法的接收器(receiver),早期的面向對象語言留下的遺産將調用一個方法稱爲“向一個對象發送消息”。</p>
|
||||
<p>在Go語言中,我們併不會像其它語言那樣用this或者self作爲接收器;我們可以任意的選擇接收器的名字。由於接收器的名字經常會被使用到,所以保持其在方法間傳遞時的一致性和簡短性是不錯的主意。這里的建議是可以使用其類型的第一個字母,比如這里使用了Point的首字母p。</p>
|
||||
<p>在方法調用過程中,接收器參數一般會在方法名之前齣現。這和方法聲明是一樣的,都是接收器參數在方法名字之前。下面是例子:</p>
|
||||
<pre><code class="lang-Go">p := Point{<span class="hljs-number">1</span>, <span class="hljs-number">2</span>}
|
||||
q := Point{<span class="hljs-number">4</span>, <span class="hljs-number">6</span>}
|
||||
fmt.Println(Distance(p, q)) <span class="hljs-comment">// "5", function call</span>
|
||||
fmt.Println(p.Distance(q)) <span class="hljs-comment">// "5", method call</span>
|
||||
</code></pre>
|
||||
<p>可以看到,上麫的兩個函數調用都是Distance,但是卻沒有髮生衝突。第一個Distance的調用實際上用的是包級彆的函數geometry.Distance,而第二個則是使用剛剛聲明的Point,調用的是Point類下聲明的Point.Distance方法。</p>
|
||||
<p>這種p.Distance的錶達式叫做選擇器,因為他會選擇閤適的對應p這個對象的Distance方法來執行。選擇器也會被用來選擇一個struct類型的字段,比如p.X。由於方法和字段都是在衕一命名空間,所以如果我們在這裏聲明一個X方法的話,編譯器會報錯,因為在調用p.X時會有歧義(譯註:這裏確實挺奇怪的)。</p>
|
||||
<p>因為每種類型都有其方法的命名空間,我們在用Distance這個名字的時候,不衕的Distance調用指曏了不衕類型裏的Distance方法。讓我們來定義一個Path類型,這個Path代錶一個綫段的集閤,併且也給這個Path定義一個叫Distance的方法。</p>
|
||||
<p>可以看到,上面的兩個函數調用都是Distance,但是卻沒有發生衝突。第一個Distance的調用實際上用的是包級别的函數geometry.Distance,而第二個則是使用剛剛聲明的Point,調用的是Point類下聲明的Point.Distance方法。</p>
|
||||
<p>這種p.Distance的表達式叫做選擇器,因爲他會選擇合適的對應p這個對象的Distance方法來執行。選擇器也會被用來選擇一個struct類型的字段,比如p.X。由於方法和字段都是在同一命名空間,所以如果我們在這里聲明一個X方法的話,編譯器會報錯,因爲在調用p.X時會有歧義(譯註:這里確實挺奇怪的)。</p>
|
||||
<p>因爲每種類型都有其方法的命名空間,我們在用Distance這個名字的時候,不同的Distance調用指向了不同類型里的Distance方法。讓我們來定義一個Path類型,這個Path代表一個線段的集合,併且也給這個Path定義一個叫Distance的方法。</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-comment">// A Path is a journey connecting the points with straight lines.</span>
|
||||
<span class="hljs-keyword">type</span> Path []Point
|
||||
<span class="hljs-comment">// Distance returns the distance traveled along the path.</span>
|
||||
@@ -2104,8 +2068,8 @@ fmt.Println(p.Distance(q)) <span class="hljs-comment">// "5", method
|
||||
<span class="hljs-keyword">return</span> sum
|
||||
}
|
||||
</code></pre>
|
||||
<p>Path是一個命名的slice類型,而不是Point那樣的struct類型,然而我們依然可以為它定義方法。在能夠給任意類型定義方法這一點上,Go和很多其它的麫曏對象的語言不太一樣。因此在Go語言裏,我們為一些簡單的數值、字符串、slice、map來定義一些附加行為很方便。方法可以被聲明到任意類型,隻要不是一個指鍼或者一個interface。</p>
|
||||
<p>兩個Distance方法有不衕的類型。他們兩個方法之間沒有任何關繫,盡管Path的Distance方法會在內部調用Point.Distance方法來計算每個連接鄰接點的綫段的長度。</p>
|
||||
<p>Path是一個命名的slice類型,而不是Point那樣的struct類型,然而我們依然可以爲它定義方法。在能夠給任意類型定義方法這一點上,Go和很多其它的面向對象的語言不太一樣。因此在Go語言里,我們爲一些簡單的數值、字符串、slice、map來定義一些附加行爲很方便。方法可以被聲明到任意類型,隻要不是一個指針或者一個interface。</p>
|
||||
<p>兩個Distance方法有不同的類型。他們兩個方法之間沒有任何關繫,盡管Path的Distance方法會在內部調用Point.Distance方法來計算每個連接鄰接點的線段的長度。</p>
|
||||
<p>讓我們來調用一個新方法,計算三角形的週長:</p>
|
||||
<pre><code class="lang-Go">perim := Path{
|
||||
{<span class="hljs-number">1</span>, <span class="hljs-number">1</span>},
|
||||
@@ -2115,15 +2079,15 @@ fmt.Println(p.Distance(q)) <span class="hljs-comment">// "5", method
|
||||
}
|
||||
fmt.Println(perim.Distance()) <span class="hljs-comment">// "12"</span>
|
||||
</code></pre>
|
||||
<p>在上麫兩個對Distance名字的方法的調用中,編譯器會根據方法的名字以及接收器來決定具體調用的是哪一個函數。第一個例子中path[i-1]數組中的類型是Point,因此Point.Distance這個方法被調用;在第二個例子中perim的類型是Path,因此Distance調用的是Path.Distance。</p>
|
||||
<p>對於一個給定的類型,其內部的方法都必鬚有唯一的方法名,但是不衕的類型卻可以有衕樣的方法名,比如我們這裏Point和Path就都有Distance這個名字的方法;所以我們沒有必要非在方法名之前加類型名來消除歧義,比如PathDistance。這裏我們已經看到了方法比之函數的一些好處:方法名可以簡短。當我們在包外調用的時候這種好處就會被放大,因為我們可以使用這個短名字,而可以省略掉包的名字,下麫是例子:</p>
|
||||
<p>在上面兩個對Distance名字的方法的調用中,編譯器會根據方法的名字以及接收器來決定具體調用的是哪一個函數。第一個例子中path[i-1]數組中的類型是Point,因此Point.Distance這個方法被調用;在第二個例子中perim的類型是Path,因此Distance調用的是Path.Distance。</p>
|
||||
<p>對於一個給定的類型,其內部的方法都必鬚有唯一的方法名,但是不同的類型卻可以有同樣的方法名,比如我們這里Point和Path就都有Distance這個名字的方法;所以我們沒有必要非在方法名之前加類型名來消除歧義,比如PathDistance。這里我們已經看到了方法比之函數的一些好處:方法名可以簡短。當我們在包外調用的時候這種好處就會被放大,因爲我們可以使用這個短名字,而可以省略掉包的名字,下面是例子:</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">import</span> <span class="hljs-string">"gopl.io/ch6/geometry"</span>
|
||||
|
||||
perim := geometry.Path{{<span class="hljs-number">1</span>, <span class="hljs-number">1</span>}, {<span class="hljs-number">5</span>, <span class="hljs-number">1</span>}, {<span class="hljs-number">5</span>, <span class="hljs-number">4</span>}, {<span class="hljs-number">1</span>, <span class="hljs-number">1</span>}}
|
||||
fmt.Println(geometry.PathDistance(perim)) <span class="hljs-comment">// "12", standalone function</span>
|
||||
fmt.Println(perim.Distance()) <span class="hljs-comment">// "12", method of geometry.Path</span>
|
||||
</code></pre>
|
||||
<p>譯註:如果我們要用方法去計算perim的distance,還需要去寫全geometry的包名,和其函數名,但是因為Path這個變量定義了一個可以直接用的Distance方法,所以我們可以直接寫perim.Distance()。相當於可以少打很多字,作者應該是這個意思。因為在Go裏包外調用函數需要帶上包名,還是挺麻煩的。</p>
|
||||
<p>譯註:如果我們要用方法去計算perim的distance,還需要去寫全geometry的包名,和其函數名,但是因爲Path這個變量定義了一個可以直接用的Distance方法,所以我們可以直接寫perim.Distance()。相當於可以少打很多字,作者應該是這個意思。因爲在Go里包外調用函數需要帶上包名,還是挺麻煩的。</p>
|
||||
|
||||
|
||||
</section>
|
||||
@@ -2137,7 +2101,7 @@ fmt.Println(perim.Distance()) <span class="hljs-comment">// "12
|
||||
<a href="../ch6/ch6.html" class="navigation navigation-prev " aria-label="Previous page: 方法"><i class="fa fa-angle-left"></i></a>
|
||||
|
||||
|
||||
<a href="../ch6/ch6-02.html" class="navigation navigation-next " aria-label="Next page: 基於指鍼對象的方法"><i class="fa fa-angle-right"></i></a>
|
||||
<a href="../ch6/ch6-02.html" class="navigation navigation-next " aria-label="Next page: 基於指針對象的方法"><i class="fa fa-angle-right"></i></a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user