在上一篇文章中,我们讲解了接口,对于很多初学者来说,接口很抽象,我们有时候不知道如何定义自己的接口,基于此,在这篇文章中,我们来学习几个Go
标准库的接口,看看Go
标准库是如何定义接口,以加深对Go
语言接口的理解。
fmt.Stringer
在开发过程,我们经常会调用fmt
包下的打印函数(如println
或printf
)将调试信息输出到控制台:
fmt.Println("test") fmt.Printf("%d\n",10)
这些打印函数会自动决定如何在控制台输出这些信息,对于自定义类型,如果我们想自定义其在控制台的输出,要怎么做呢?
fmt
包的Stringer
用于定义类型的格式化输出,该接口的定义如下:
type Stringer interface { String() string }
对于实现了Stringer
接口的类型,打印函数会自动调用该类型的String()
方法,将该方法的返回值输出到控制台,比如我们自定义一个Reason
类型,用于表示季节:
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 }
实现Stringer接口后,就可以将Reason
类以中文的格式打印出来了:
func (r Reason) String() string { return ReasonText[r] //自定义输出:将数值转化为文本 } 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
除了格式化输出信息外,排序功能也是开发中经常用到的,Go
标准库的sort
包的Sort()
就是常用的排序函数,该函数定义如下:
func Sort(data Interface) { n := data.Len() quickSort(data, 0, n, maxDepth(n)) }
可以看到,Sort
函数接收一个Inferface
类型的参数,Interface
类型是一个接口,其定义如下:
type Interface interface { Len() int Less(i, j int) bool Swap(i, j int) }
Interface
类型的Len
方法用于返回长度,Less
方法用于元素比较大小,Swap
方法实现元素位置交换,任何拥有这个方法的类型,都可以传递给sort.Sort
进行排序。
下面是一个实现sort.Interface
接口,并调用sort.Sort
函数的示例:
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
网络数据的读取与发送、文件的读取与写入,本质都是写入或取出一段字节数据(即字节数组),Go标准库对字节的读取与写入抽象为io
包的Reader
和Writer
接口:
type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) }
在Go标准库内有很多实现了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) }
上面我们调用io.Copy
方法将请求到的数据输出到控制台,io.Copy
函数定义如下:
func Copy(dst Writer, src Reader) (written int64, err error) { return copyBuffer(dst, src, nil) }
可以看到这个方法接收的参数就是Writer
和Reader
接口,我们也可以自定义类型来实现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
语言的函数支持多个返回值,一般推荐把error
类型作为函数最后一个返回值,用于告诉调用者函数调用是否发生错误,error
类型实际上就是一个接口:
type error interface { Error() string }
可以看到error
只定义了一个方法,该方法返回一个字符串的错误信息,我们可以使用errors
包的方法创建并返回一个error
类型:
var err error = errors.New("Not Found")
也可以在实现error
接口的基础,包含更多的错误信息,方便调用者判断错误类型:
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
请求应该实现的方法。
type Handler interface { ServeHTTP(w ResponseWriter, r *Request) }
在Go
语言中,只需要简单的几行代码便可以启动一个Web
服务器:
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()
会将我们自己的匿名函数封装为HandlerFunc
函数,HandlerFunc
函数的定义如下,可以看到这个函数实现了Handler
接口:
type HandlerFunc func(ResponseWriter, *Request) func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) }
关于Go的Web开发部分,我们后面在其他文章再详细讲解!
小结
几个Go接口讲解下来,你会发现,其实Go标准库定义的接口简单且通用,一个接口就只描述一种行为,这就是Go语言的编程哲学是一个接口只做一件事,只完成一个功能,将多个功能堆砌在同一个接口内是不可取的。
另外也不要在开发某个具体类型前预定义好接口,而是当多个类型有共同行为但却有不同实现的时候,才用接口加以概括和描述。
到此这篇关于Golang六个常用接口的使用总结的文章就介绍到这了,更多相关Golang接口内容请搜索好代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持好代码网!