公众号:程序员读书;欢迎重视
在上一篇文章中,咱们解说了接口,对于许多初学者来说,接口很抽象,咱们有时候不知道怎么界说自己的接口,基于此,在这篇文章中,咱们来学习几个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言语的编程哲学是一个接口只做一件事,只完结一个功能,将多个功能堆砌在同一个接口内是不可取的。
别的也不要在开发某个具体类型前预界说好接口,而是当多个类型有共同行为但却有不同完结的时候,才用接口加以归纳和描述。