Golang六个常用接口的使用总结

 更新时间:2023年07月31日 09:50:10   作者:程序员读书  
在这篇文章中,小编来带大家学习几个Go标准库的接口,看看Go标准库是如何定义接口,以加深对Go语言接口的理解,感兴趣的小伙伴快跟随小编一起了解一下吧

在上一篇文章中,我们讲解了接口,对于很多初学者来说,接口很抽象,我们有时候不知道如何定义自己的接口,基于此,在这篇文章中,我们来学习几个Go标准库的接口,看看Go标准库是如何定义接口,以加深对Go语言接口的理解。

fmt.Stringer

在开发过程,我们经常会调用fmt包下的打印函数(如printlnprintf)将调试信息输出到控制台:

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包的ReaderWriter接口:

type Reader interface {
	Read(p []byte) (n int, err error)
}
type Writer interface {
	Write(p []byte) (n int, err error)
}

在Go标准库内有很多实现了io.Readerio.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)
}

可以看到这个方法接收的参数就是WriterReader接口,我们也可以自定义类型来实现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接口内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • golang实现sql结果集以json格式输出的方法

    golang实现sql结果集以json格式输出的方法

    这篇文章主要介绍了golang实现sql结果集以json格式输出的方法,涉及Go语言针对sql结果集的遍历、转换及json格式相关操作技巧,需要的朋友可以参考下
    2017-03-03
  • Go语言crypto包创建自己的密码加密工具实现示例

    Go语言crypto包创建自己的密码加密工具实现示例

    Go语言借助它的简单性和强大的标准库,实现一个自己的密码加密工具,本文将会结合代码示例深入探讨如何使用Go语言的crypto包来实现自己的加密工具
    2023-11-11
  • Go语言内建函数cap的实现示例

    Go语言内建函数cap的实现示例

    cap 是一个常用的内建函数,它用于获取某些数据结构的容量,本文主要介绍了Go语言内建函数cap的实现示例,具有一定的参考价值,感兴趣的可以了解一下
    2024-08-08
  • Go语言二维数组的传参方式

    Go语言二维数组的传参方式

    这篇文章主要介绍了Go语言二维数组的传参方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • Go语言中log日志库的介绍

    Go语言中log日志库的介绍

    本文给大家介绍Go语言中log日志库的概念使用技巧,log包定义了Logger类型,该类型提供了一些格式化输出的方法,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-10-10
  • Golang多线程下载器实现高效快速地下载大文件

    Golang多线程下载器实现高效快速地下载大文件

    Golang多线程下载器是一种高效、快速地下载大文件的方法。Golang语言天生支持并发和多线程,可以轻松实现多线程下载器的开发。通过使用Golang的协程和通道,可以将下载任务分配到多个线程中并行处理,提高了下载的效率和速度
    2023-05-05
  • 一起来用GoLand开发第一个Go程序

    一起来用GoLand开发第一个Go程序

    当您在编辑器中工作时GoLand 会分析您的代码,寻找优化方法,并检测潜在和实际问题,下面这篇文章主要给大家介绍了关于用GoLand开发第一个Go程序的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-12-12
  • golang fmt占位符的使用详解

    golang fmt占位符的使用详解

    这篇文章主要介绍了golang fmt占位符的使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Golang中使用不定数量空格分割字符串的方法

    Golang中使用不定数量空格分割字符串的方法

    有这样一个使用空格分割字符串的场景,字符串中被分割的子串之间的空格数量不确定,有一个两个或者多个空格,这种场景下,使用最容易想到的strings.Split函数就做不到了,本文接下来就介绍几种行之有效的方法,需要的朋友可以参考下
    2023-07-07
  • 详解go语言 make(chan int, 1) 和 make (chan int) 的区别

    详解go语言 make(chan int, 1) 和 make (chan int) 的区别

    这篇文章主要介绍了go语言 make(chan int, 1) 和 make (chan int) 的区别,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-01-01

最新评论