Golang六個常用接口的使用總結(jié)
在上一篇文章中,我們講解了接口,對于很多初學(xué)者來說,接口很抽象,我們有時候不知道如何定義自己的接口,基于此,在這篇文章中,我們來學(xué)習(xí)幾個Go
標(biāo)準(zhǔn)庫的接口,看看Go
標(biāo)準(zhǔn)庫是如何定義接口,以加深對Go
語言接口的理解。
fmt.Stringer
在開發(fā)過程,我們經(jīng)常會調(diào)用fmt
包下的打印函數(shù)(如println
或printf
)將調(diào)試信息輸出到控制臺:
fmt.Println("test") fmt.Printf("%d\n",10)
這些打印函數(shù)會自動決定如何在控制臺輸出這些信息,對于自定義類型,如果我們想自定義其在控制臺的輸出,要怎么做呢?
fmt
包的Stringer
用于定義類型的格式化輸出,該接口的定義如下:
type Stringer interface { String() string }
對于實(shí)現(xiàn)了Stringer
接口的類型,打印函數(shù)會自動調(diào)用該類型的String()
方法,將該方法的返回值輸出到控制臺,比如我們自定義一個Reason
類型,用于表示季節(jié):
package main type Reason uint const ( SPRING Reason = iota + 1 SUMMER AUTUMN WINTER ) func main() { fmt.Println(SPRING) //輸出:1 fmt.Println(SUMMER) //輸出:2 fmt.Println(AUTUMN) //輸出:3 fmt.Println(WINTER) //輸出:4 }
實(shí)現(xiàn)Stringer接口后,就可以將Reason
類以中文的格式打印出來了:
func (r Reason) String() string { return ReasonText[r] //自定義輸出:將數(shù)值轉(zhuǎn)化為文本 } var ReasonText = map[Reason]string{ SPRING: "春天", SUMMER: "夏天", AUTUMN: "秋天", WINTER: "冬天", } func main() { fmt.Println(SPRING) //輸出:春天 fmt.Println(SUMMER) //輸出:夏天 fmt.Println(AUTUMN) //輸出:秋天 fmt.Println(WINTER) //輸出:冬天 }
sort.Interface
除了格式化輸出信息外,排序功能也是開發(fā)中經(jīng)常用到的,Go
標(biāo)準(zhǔn)庫的sort
包的Sort()
就是常用的排序函數(shù),該函數(shù)定義如下:
func Sort(data Interface) { n := data.Len() quickSort(data, 0, n, maxDepth(n)) }
可以看到,Sort
函數(shù)接收一個Inferface
類型的參數(shù),Interface
類型是一個接口,其定義如下:
type Interface interface { Len() int Less(i, j int) bool Swap(i, j int) }
Interface
類型的Len
方法用于返回長度,Less
方法用于元素比較大小,Swap
方法實(shí)現(xiàn)元素位置交換,任何擁有這個方法的類型,都可以傳遞給sort.Sort
進(jìn)行排序。
下面是一個實(shí)現(xiàn)sort.Interface
接口,并調(diào)用sort.Sort
函數(shù)的示例:
package main import ( "fmt" "sort" ) type Student struct { ID int Name string Score int } type Students []Student func (s Students) Len() int { return len(s) } func (s Students) Less(i, j int) bool { return s[i].Score > s[j].Score } func (s Students) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func main() { students := []Student{ {ID: 1, Name: "A", Score: 95}, {ID: 2, Name: "B", Score: 100}, {ID: 3, Name: "C", Score: 90}, {ID: 4, Name: "D", Score: 80}, } sort.Sort(Students(students)) fmt.Println(students) }
io.Reader和io.Writer
網(wǎng)絡(luò)數(shù)據(jù)的讀取與發(fā)送、文件的讀取與寫入,本質(zhì)都是寫入或取出一段字節(jié)數(shù)據(jù)(即字節(jié)數(shù)組),Go標(biāo)準(zhǔn)庫對字節(jié)的讀取與寫入抽象為io
包的Reader
和Writer
接口:
type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) }
在Go標(biāo)準(zhǔn)庫內(nèi)有很多實(shí)現(xiàn)了io.Reader
和io.Writer
接口,比如os.File
或者Response.Boy
:
package main import ( "io" "net/http" "os" ) func main() { url := "" response, err := http.Get(url) if err != nil { panic(err) } //os.Stdout是os.File類型 io.Copy(os.Stdout, response.Body) }
上面我們調(diào)用io.Copy
方法將請求到的數(shù)據(jù)輸出到控制臺,io.Copy
函數(shù)定義如下:
func Copy(dst Writer, src Reader) (written int64, err error) { return copyBuffer(dst, src, nil) }
可以看到這個方法接收的參數(shù)就是Writer
和Reader
接口,我們也可以自定義類型來實(shí)現(xiàn)Writer
或者Reader
接口:
package main import ( "fmt" "io" "net/http" ) type Data string func (d *Data) Write(p []byte) (n int, err error) { n = len(p) *d = Data(string(p)) return n, nil } func main() { url := "" response, err := http.Get(url) if err != nil { panic(err) } var d Data io.Copy(&d, response.Body) fmt.Println(d) }
error
Go
語言的函數(shù)支持多個返回值,一般推薦把error
類型作為函數(shù)最后一個返回值,用于告訴調(diào)用者函數(shù)調(diào)用是否發(fā)生錯誤,error
類型實(shí)際上就是一個接口:
type error interface { Error() string }
可以看到error
只定義了一個方法,該方法返回一個字符串的錯誤信息,我們可以使用errors
包的方法創(chuàng)建并返回一個error
類型:
var err error = errors.New("Not Found")
也可以在實(shí)現(xiàn)error
接口的基礎(chǔ),包含更多的錯誤信息,方便調(diào)用者判斷錯誤類型:
package main import ( "fmt" "os" ) type FileNotFound struct { Message string FileName string err error } func (f FileNotFound) Error() string { return f.Message } func GetLogFile(fileName string) (*os.File, error) { f, err := os.Open(fileName) if err != nil { return nil, &FileNotFound{FileName: fileName, err: err, Message: "Not found"} } return f, nil } func main() { var err error f, err = GetLogFile("1.txt") if e, ok := err.(FileNotFound); ok { fmt.Println(e.Message) } }
http.Handler
http
包的Handler
接口定義如下,該接口定義了處理HTTP
請求應(yīng)該實(shí)現(xiàn)的方法。
type Handler interface { ServeHTTP(w ResponseWriter, r *Request) }
在Go
語言中,只需要簡單的幾行代碼便可以啟動一個Web
服務(wù)器:
package main import "net/http" func main() { http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("User Info")) }) http.ListenAndServe(":8080", nil) }
http.HandleFunc()
會將我們自己的匿名函數(shù)封裝為HandlerFunc
函數(shù),HandlerFunc
函數(shù)的定義如下,可以看到這個函數(shù)實(shí)現(xiàn)了Handler
接口:
type HandlerFunc func(ResponseWriter, *Request) func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) }
關(guān)于Go的Web開發(fā)部分,我們后面在其他文章再詳細(xì)講解!
小結(jié)
幾個Go接口講解下來,你會發(fā)現(xiàn),其實(shí)Go標(biāo)準(zhǔn)庫定義的接口簡單且通用,一個接口就只描述一種行為,這就是Go語言的編程哲學(xué)是一個接口只做一件事,只完成一個功能,將多個功能堆砌在同一個接口內(nèi)是不可取的。
另外也不要在開發(fā)某個具體類型前預(yù)定義好接口,而是當(dāng)多個類型有共同行為但卻有不同實(shí)現(xiàn)的時候,才用接口加以概括和描述。
到此這篇關(guān)于Golang六個常用接口的使用總結(jié)的文章就介紹到這了,更多相關(guān)Golang接口內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang實(shí)現(xiàn)sql結(jié)果集以json格式輸出的方法
這篇文章主要介紹了golang實(shí)現(xiàn)sql結(jié)果集以json格式輸出的方法,涉及Go語言針對sql結(jié)果集的遍歷、轉(zhuǎn)換及json格式相關(guān)操作技巧,需要的朋友可以參考下2017-03-03Go語言crypto包創(chuàng)建自己的密碼加密工具實(shí)現(xiàn)示例
Go語言借助它的簡單性和強(qiáng)大的標(biāo)準(zhǔn)庫,實(shí)現(xiàn)一個自己的密碼加密工具,本文將會結(jié)合代碼示例深入探討如何使用Go語言的crypto包來實(shí)現(xiàn)自己的加密工具2023-11-11Go語言內(nèi)建函數(shù)cap的實(shí)現(xiàn)示例
cap 是一個常用的內(nèi)建函數(shù),它用于獲取某些數(shù)據(jù)結(jié)構(gòu)的容量,本文主要介紹了Go語言內(nèi)建函數(shù)cap的實(shí)現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下2024-08-08Golang多線程下載器實(shí)現(xiàn)高效快速地下載大文件
Golang多線程下載器是一種高效、快速地下載大文件的方法。Golang語言天生支持并發(fā)和多線程,可以輕松實(shí)現(xiàn)多線程下載器的開發(fā)。通過使用Golang的協(xié)程和通道,可以將下載任務(wù)分配到多個線程中并行處理,提高了下載的效率和速度2023-05-05詳解go語言 make(chan int, 1) 和 make (chan int) 的區(qū)別
這篇文章主要介紹了go語言 make(chan int, 1) 和 make (chan int) 的區(qū)別,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2020-01-01