首頁 > 後端開發 > Golang > 主體

go語言eof錯誤是什麼

青灯夜游
發布: 2023-02-06 14:10:26
原創
8485 人瀏覽過

在go語言中,eof是指檔案結尾錯誤,是Go語言中最重要的錯誤變量,存在於io套件中,用來表示輸入流的結尾。因為每個檔案都有一個結尾,所以「io.EOF」很多時候並不能算是一個錯誤,它更重要的是表示一個輸入流結束了。

go語言eof錯誤是什麼

本教學操作環境:windows7系統、GO 1.18版本、Dell G3電腦。

golang 檔案結尾錯誤(EOF)

函數經常會傳回多種錯誤,這對終端使用者來說可能會很有趣,但對程序而言,這使得情況變得複雜。很多時候,程式必須根據錯誤類型,做出不同的回應。讓我們考慮這樣一個例子:

從檔案讀取n個位元組。如果n等於檔案的長度,讀取過程的任何錯誤都表示失敗。如果n小於檔案的長度,呼叫者會重複的讀取固定大小的資料直到檔案結束。這會導致呼叫者必須分別處理由檔案結束引起的各種錯誤。

基於這樣的原因,io套件保證任何由檔案結束引起的讀取失敗都會回傳同一個錯誤-io.EOF,該錯誤在io套件中定義:

package io
import "errors"
// EOF is the error returned by Read when no more input is available.
var EOF = errors.New("EOF")
登入後複製

認識io.EOF

io.EOF是io套件中的變數, 表示檔案結束的錯誤:

package io23var EOF = errors.New("EOF")
登入後複製

#也透過以下指令查看詳細文件:

$ go doc io.EOF
var EOF = errors.New("EOF")
EOF is the error returned by Read when no more input is available. Functions
should return EOF only to signal a graceful end of input. If the EOF occurs
unexpectedly in a structured data stream, the appropriate error is either
ErrUnexpectedEOF or some other error giving more detail.
$
登入後複製

io.EOF大約可以算是Go語言中最重要的錯誤變數了, 它用來表示輸入流的結尾. 因為每個檔案都有一個結尾, 所以io.EOF很多時候並不能算是一個錯誤, 它更重要的是表示一個輸入流結束了。

io.EOF設計的缺陷

#可惜標準庫中的io.EOF的設計是有問題的. 首先EOF是End- Of-File的縮寫, 根據Go語言的習慣大寫字母縮寫一般表示常數. 可惜io.EOF被錯誤地定義成了變數, 這導致了API權限的擴散. 而最小化API權限是任何一個模組或函數設計的最高要求. 透過最小化的權限, 可以儘早發現程式碼中不必要的錯誤.

例如Go語言一個重要的安全設計就是禁止隱式的類型轉換. 因此這個設計我們就可以很容易發現程式的BUG. 另外Go語言禁止定義沒有被使用到的局部變數(函數參數除外, 因此函數參數是函數介面的一個部分)和禁止導入沒有用到的包都是最小化權限的最佳實務.這些最小API權限的設計不僅改進了程式的品質, 也提高了編譯工具的性能和輸出的目標檔案.

因為EOF被定義成一個變數, 這導致了該變數可能會被惡意改變. 下面的程式碼就是一種優雅的埋坑方式:

func init() {2    io.EOF = nil3}
登入後複製

這雖然是一個段子, 但是卻真實地暴漏了EOF接口的設計缺陷: 它存在嚴重的安全隱患. 變量的類型似乎也在暗示使用者可以放心地修改變數的值. 因此說EOF是一個不安全也不優雅的設計.

io.EOF改為常數

一個顯然的改進思路是將io.EOF定義為常數. 但是因為EOF對應一個表示error接口類型, 而Go語言目前的常量語法並不支持定義常量類型的接口. 但是我們可以通過一些技巧繞過這個限制.

Go語言的常數有bool/int/float/string/nil這幾種主要類型. 常數不僅僅不包含接口等複雜類型, 甚至連常量的數組或結構體都不支援! 不過常數有一個重要的擴充規則: 以bool/int/float/string/nil為基礎型別定義的新型別也支援常數.

例如, 我們重新定義一個字串型別, 它也可以支援常數的:

type MyString string2const name MyString = "chai2010"
登入後複製

這個例子中MyString是一個新定義的類型, 可以定義這種類型的常數, 因為它的底層的string類型是支援常數的.

那麼io.EOF的底層型別是什麼呢? EOF是透過errors.New("EOF")定義的, 下面是這個函數的實現:

package errors 
// New returns an error that formats as the given text. 
func New(text string) error {
    return &errorString{text} 
} 

// errorString is a trivial implementation of error. 
type errorString struct {
    s string
}

func (e *errorString) Error() string {
    return e.s
}
登入後複製

因此io.EOF底層的型別是errors .errorString結構體. 而結構體類型是不支援定義常數的. 不過errors.errorString結構體中只有一個字串型別, io.EOF對應的錯誤字串正是"EOF".

我們可以為EOF重新實作一個以字串為底層類型的新錯誤類型:

package io

type errorString string

func (e errorString) Error() string {
    return string(e)
}
登入後複製

這個新的io.errorString實作了兩個特性: 首先是滿足了error介面; 其次它是基於string類型重新定義, 因此支援定義常數. 因此我們可以基於errorString重新將io.EOF定義為常數:

const EOF = errorString("EOF")
登入後複製

這樣EOF就變成了編譯時可以確定的常數類型, 常數的值依然是“EOF”字串. 但是也帶來了新的問題: EOF已經不再是一個介面類型, 它會破壞舊程式碼的兼容性嗎?

【相關推薦:Go影片教學程式設計教學

以上是go語言eof錯誤是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板