mirror of
				https://github.com/gopl-zh/gopl-zh.github.com.git
				synced 2025-11-03 19:31:35 +00:00 
			
		
		
		
	fix md
This commit is contained in:
		@@ -1,7 +1,9 @@
 | 
				
			|||||||
### 7.5.1.  警告:一個包含nil指針的接口不是nil接口
 | 
					### 7.5.1.  警告:一個包含nil指針的接口不是nil接口
 | 
				
			||||||
 | 
					
 | 
				
			||||||
一個不包含任何值的nil接口值和一個剛好包含nil指針的接口值是不同的。這個細微區别産生了一個容易絆倒每個Go程序員的陷阱。
 | 
					一個不包含任何值的nil接口值和一個剛好包含nil指針的接口值是不同的。這個細微區别産生了一個容易絆倒每個Go程序員的陷阱。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
思考下面的程序。當debug變量設置爲true時,main函數會將f函數的輸出收集到一個bytes.Buffer類型中。
 | 
					思考下面的程序。當debug變量設置爲true時,main函數會將f函數的輸出收集到一個bytes.Buffer類型中。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```go
 | 
					```go
 | 
				
			||||||
const debug = true
 | 
					const debug = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,12 +26,15 @@ func f(out io.Writer) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
我們可能會預計當把變量debug設置爲false時可以禁止對輸出的收集,但是實際上在out.Write方法調用時程序發生了panic:
 | 
					我們可能會預計當把變量debug設置爲false時可以禁止對輸出的收集,但是實際上在out.Write方法調用時程序發生了panic:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```go
 | 
					```go
 | 
				
			||||||
if out != nil {
 | 
					if out != nil {
 | 
				
			||||||
    out.Write([]byte("done!\n")) // panic: nil pointer dereference
 | 
					    out.Write([]byte("done!\n")) // panic: nil pointer dereference
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
當main函數調用函數f時,它給f函數的out參數賦了一個\*bytes.Buffer的空指針,所以out的動態值是nil。然而,它的動態類型是\*bytes.Buffer,意思就是out變量是一個包含空指針值的非空接口(如圖7.5),所以防禦性檢査out!=nil的結果依然是true。
 | 
					當main函數調用函數f時,它給f函數的out參數賦了一個\*bytes.Buffer的空指針,所以out的動態值是nil。然而,它的動態類型是\*bytes.Buffer,意思就是out變量是一個包含空指針值的非空接口(如圖7.5),所以防禦性檢査out!=nil的結果依然是true。
 | 
				
			||||||
 | 
					
 | 
				
			||||||

 | 
					
 | 
				
			||||||
@@ -37,6 +42,7 @@ if out != nil {
 | 
				
			|||||||
動態分配機製依然決定(\*bytes.Buffer).Write的方法會被調用,但是這次的接收者的值是nil。對於一些如\*os.File的類型,nil是一個有效的接收者(§6.2.1),但是\*bytes.Buffer類型不在這些類型中。這個方法會被調用,但是當它嚐試去獲取緩衝區時會發生panic。
 | 
					動態分配機製依然決定(\*bytes.Buffer).Write的方法會被調用,但是這次的接收者的值是nil。對於一些如\*os.File的類型,nil是一個有效的接收者(§6.2.1),但是\*bytes.Buffer類型不在這些類型中。這個方法會被調用,但是當它嚐試去獲取緩衝區時會發生panic。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
問題在於盡管一個nil的\*bytes.Buffer指針有實現這個接口的方法,它也不滿足這個接口具體的行爲上的要求。特别是這個調用違反了(\*bytes.Buffer).Write方法的接收者非空的隱含先覺條件,所以將nil指針賦給這個接口是錯誤的。解決方案就是將main函數中的變量buf的類型改爲io.Writer,因此可以避免一開始就將一個不完全的值賦值給這個接口:
 | 
					問題在於盡管一個nil的\*bytes.Buffer指針有實現這個接口的方法,它也不滿足這個接口具體的行爲上的要求。特别是這個調用違反了(\*bytes.Buffer).Write方法的接收者非空的隱含先覺條件,所以將nil指針賦給這個接口是錯誤的。解決方案就是將main函數中的變量buf的類型改爲io.Writer,因此可以避免一開始就將一個不完全的值賦值給這個接口:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```go
 | 
					```go
 | 
				
			||||||
var buf io.Writer
 | 
					var buf io.Writer
 | 
				
			||||||
if debug {
 | 
					if debug {
 | 
				
			||||||
@@ -44,4 +50,5 @@ if debug {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
f(buf) // OK
 | 
					f(buf) // OK
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
現在我們已經把接口值的技巧都講完了,讓我們來看更多的一些在Go標準庫中的重要接口類型。在下面的三章中,我們會看到接口類型是怎樣用在排序,web服務,錯誤處理中的。
 | 
					現在我們已經把接口值的技巧都講完了,讓我們來看更多的一些在Go標準庫中的重要接口類型。在下面的三章中,我們會看到接口類型是怎樣用在排序,web服務,錯誤處理中的。
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -107,3 +107,5 @@ fmt.Printf("%T\n", w) // "*bytes.Buffer"
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
在fmt包內部,使用反射來獲取接口動態類型的名稱。我們會在第12章中學到反射相關的知識。
 | 
					在fmt包內部,使用反射來獲取接口動態類型的名稱。我們會在第12章中學到反射相關的知識。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% include "./ch7-05-1.md" %}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user