2015-12-09 07:45:11 +00:00
|
|
|
|
## 7.8. error接口
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
從本書的開始,我們就已經創建和使用過神祕的預定義error類型,而且沒有解釋它究竟是什麽。實際上它就是interface類型,這個類型有一個返迴錯誤信息的單一方法:
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
```go
|
|
|
|
|
type error interface {
|
2016-01-18 02:52:21 +00:00
|
|
|
|
Error() string
|
2016-01-14 14:46:55 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
創建一個error最簡單的方法就是調用errors.New函數,它會根據傳入的錯誤信息返迴一個新的error。整個errors包僅隻有4行:
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
```go
|
|
|
|
|
package errors
|
2015-12-09 07:45:11 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
func New(text string) error { return &errorString{text} }
|
|
|
|
|
|
|
|
|
|
type errorString struct { text string }
|
|
|
|
|
|
|
|
|
|
func (e *errorString) Error() string { return e.text }
|
|
|
|
|
```
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
承載errorString的類型是一個結構體而非一個字符串,這是爲了保護它表示的錯誤避免粗心(或有意)的更新。併且因爲是指針類型*errorString滿足error接口而非errorString類型,所以每個New函數的調用都分配了一個獨特的和其他錯誤不相同的實例。我們也不想要重要的error例如io.EOF和一個剛好有相同錯誤消息的error比較後相等。
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
```go
|
|
|
|
|
fmt.Println(errors.New("EOF") == errors.New("EOF")) // "false"
|
|
|
|
|
```
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
調用errors.New函數是非常稀少的,因爲有一個方便的封裝函數fmt.Errorf,它還會處理字符串格式化。我們曾多次在第5章中用到它。
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
```go
|
|
|
|
|
package fmt
|
|
|
|
|
|
|
|
|
|
import "errors"
|
|
|
|
|
|
|
|
|
|
func Errorf(format string, args ...interface{}) error {
|
|
|
|
|
return errors.New(Sprintf(format, args...))
|
|
|
|
|
}
|
|
|
|
|
```
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
雖然*errorString可能是最簡單的錯誤類型,但遠非隻有它一個。例如,syscall包提供了Go語言底層繫統調用API。在多個平台上,它定義一個實現error接口的數字類型Errno,併且在Unix平台上,Errno的Error方法會從一個字符串表中査找錯誤消息,如下面展示的這樣:
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
```go
|
|
|
|
|
package syscall
|
|
|
|
|
|
|
|
|
|
type Errno uintptr // operating system error code
|
|
|
|
|
|
|
|
|
|
var errors = [...]string{
|
2016-01-18 02:52:21 +00:00
|
|
|
|
1: "operation not permitted", // EPERM
|
|
|
|
|
2: "no such file or directory", // ENOENT
|
|
|
|
|
3: "no such process", // ESRCH
|
|
|
|
|
// ...
|
2016-01-14 14:46:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e Errno) Error() string {
|
2016-01-18 02:52:21 +00:00
|
|
|
|
if 0 <= int(e) && int(e) < len(errors) {
|
|
|
|
|
return errors[e]
|
|
|
|
|
}
|
|
|
|
|
return fmt.Sprintf("errno %d", e)
|
2016-01-14 14:46:55 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
下面的語句創建了一個持有Errno值爲2的接口值,表示POSIX ENOENT狀況:
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
```go
|
|
|
|
|
var err error = syscall.Errno(2)
|
|
|
|
|
fmt.Println(err.Error()) // "no such file or directory"
|
|
|
|
|
fmt.Println(err) // "no such file or directory"
|
|
|
|
|
```
|
2016-01-18 01:53:55 +00:00
|
|
|
|
|
2016-01-14 14:46:55 +00:00
|
|
|
|
err的值圖形化的呈現在圖7.6中。
|
|
|
|
|
|
|
|
|
|
![](../images/ch7-06.png)
|
|
|
|
|
|
2016-01-14 14:49:54 +00:00
|
|
|
|
Errno是一個繫統調用錯誤的高效表示方式,它通過一個有限的集合進行描述,併且它滿足標準的錯誤接口。我們會在第7.11節了解到其它滿足這個接口的類型。
|