Go interface 接口的最佳实践经验分享

目录
  • Go语言-Go 接口的最佳实践
    • 什么是Golang中的interface
    • 编写接口的最佳实践
      • 1. 保持interfaces足够小
      • 2. Interfaces Should Have No Knowledge of Satisfying Types
      • 3. 接口不是类
    • 有关接口的更多信息
      • 空的接口
      • Zero value of an interface
      • 指针上的接口

Go语言-Go 接口的最佳实践

原文连接:https://blog.boot.dev/golang/golang-interfaces/

Go 中的接口允许我们暂时将不同的类型视为相同的数据类型,因为这两种类型实现相同的行为。它们是Go程序员工具箱的核心,并且经常被新的Go开发人员不正确地使用,导致代码不可读且经常有错误。

什么是Golang中的interface

In Go, an interface is a custom type that other types are able to implement, which gives Go developers a powerful way to use abstraction. Interfaces are named collections of method signatures, and when other types implement all the required methods, they implicitly implement the interface.

在 Go 中,接口是其他类型可以实现的自定义类型,这为 Go 开发人员提供了使用抽象的强大方式。接口是方法签名的集合,当其他类型实现所有需要的方法时,它们隐式地实现了接口。

例如,Go 中的errors是接口,标准error接口很简单,一个类型要被认为是error,所需要做的就是定义一个 Error ()方法,该方法不接受任何参数,并返回一个字符串。

type error interface {
    Error() string
}

错误error的简单性使得编写日志和metrics 实现更加容易。让我们定义一个表示网络问题的结构体:

type networkProblem struct {
	message string
	code    int
}

然后我们可以定义一个 Error ()方法:

func (np networkProblem) Error() string {
	return fmt.Sprintf("network error! message: %s, code: %v", np.message, np.code)
}

现在,我们可以在接受错误的任何地方使用 networkProblem struct 的实例。

func handleErr(err error) {
	fmt.Println(err.Error())
}
np := networkProblem{
	message: "we received a problem",
	code:    404,
}
handleErr(np)
// prints "network error! message: we received a problem, code: 404"

编写接口的最佳实践

编写干净的接口是困难的。坦率地说,任何时候你都在处理代码中的抽象,如果你不小心的话,简单可以很快变成复杂。让我们回顾一下保持interfaces整洁的一些经验法则。

  • Keep interfaces small 保持interfaces足够小
  • Interfaces should have no knowledge of satisfying types 接口应该没有令人满意的类型的知识
  • Interfaces are not classes 接口不是类

1. 保持interfaces足够小

If there is only one piece of advice that you take away from this article, make it this: keep interfaces small! Interfaces are meant to define the minimal behavior necessary to accurately represent an idea or concept.

如果您从本文中只得到了一条建议,那就是: 保持接口小一些!接口意味着定义精确表示一个想法或概念所需的最小行为。

下面是一个大型接口的标准 HTTP package的例子,它是定义最小行为的一个很好的例子:

type File interface {
    io.Closer
    io.Reader
    io.Seeker
    Readdir(count int) ([]os.FileInfo, error)
    Stat() (os.FileInfo, error)
}

Any type that satisfies the interface’s behaviors can be considered by the HTTP package as a File. This is convenient because the HTTP package doesn’t need to know if it’s dealing with a file on disk, a network buffer, or a simple []byte.

任何满足接口行为的类型都可以被 HTTP package 视为File。这很方便,因为 HTTP package 不需要知道它是在处理磁盘上的文件、还是网络缓冲区或是[]byte

2. Interfaces Should Have No Knowledge of Satisfying Types

An interface should define what is necessary for other types to classify as a member of that interface. They shouldn’t be aware of any types that happen to satisfy the interface at design time.

接口应该定义其他类型作为该接口的成员所必需的内容。他们不应该知道在设计时为了满足接口而发生的任何类型。

例如,假设我们正在构建一个接口来描述定义汽车所必需的构成元素。

type car interface {
	Color() string
	Speed() int
	IsFiretruck() bool
}

Color() and Speed() make perfect sense, they are methods confined to the scope of a car. IsFiretruck() is an anti-pattern. We are forcing all cars to declare whether or not they are firetrucks. In order for this pattern to make any amount of sense, we would need a whole list of possible subtypes. IsPickup(), IsSedan(), IsTank()… where does it end??

Color()Speed()非常合理,它们是限制在汽车范围内的方法。IsFiretruck ()是一个反模式。我们正在强制所有的汽车申报它们是否是消防车。为了使这个模式具有任何意义,我们需要一个可能的子类型的完整列表。IsPickup () ,IsSedan () ,IsTank () … 它在哪里结束?

Instead, the developer should have relied on the native functionality of type assertion to derive the underlying type when given an instance of the car interface. Or, if a sub-interface is needed, it can be defined as:

相反,当给定汽车接口的实例时,开发人员应该依赖于类型断言的原生功能来派生基础类型。或者,如果需要子接口,可以将其定义为:

type firetruck interface {
	car
	HoseLength() int
}

它继承了汽车所需的方法,并增加了一个额外的所需方法,使汽车一辆消防车。

3. 接口不是类

  • Interfaces are not classes, they are slimmer. 接口不是类,它们更小
  • Interfaces don’t have constructors or deconstructors that require that data is created or destroyed. 接口没有要求创建或销毁数据的构造函数或解构函数
  • Interfaces aren’t hierarchical by nature, though there is syntactic sugar to create interfaces that happen to be supersets of other interfaces. 接口本质上并不具有层次性,尽管在创建恰好是其他接口的超集的接口时存在语法糖
  • Interfaces define function signatures, but not underlying behavior. Making an interface often won’t 接口定义函数签名,但不定义底层行为。制作interface通常不会在结构方法方面不干扰您的代码。例如,如果五种类型满足错误接口,那么它们都需要自己的版本的Error() function. 函数

有关接口的更多信息

空的接口

空接口没有指定任何方法,因此 Go 中的每个类型都实现了空接口。

interface{}

It’s for this reason that developers sometimes use a map[string]interface{} to work with arbitrary JSON data, although I recommend using anonymous structs instead where possible.

出于这个原因,开发人员有时使用 map[string]interface{}来处理任意 JSON 数据,尽管我推荐在可能的情况下使用匿名结构

Zero value of an interface

Interfaces can be nil, in fact, it’s their zero value. That’s why when we check for errors in Go, we’re always checking if err != nil, because err is an interface.

接口可以是 nil,事实上,这是它们的零值。这就是为什么当我们在 Go 中检查错误时,我们总是检查err != nil,因为 err 是一个接口。

指针上的接口

It’s a common “gotcha” in Go to implement a method on a pointer type and expect the underlying type to implement the interface, it doesn’t work like that.

在 Go 中,在指针类型上实现一个方法并期望底层类型实现接口是一个常见的“明白了”,它不是这样工作的。

type rectangle interface {
    height() int
    width() int
}

type square struct {
    length int
}

func (sq *square) width() int {
    return sq.length
}

func (sq *square) height() int {
    return sq.length
}

Though you may expect it to, in this example the square type does not implement the rectangle interface. The *square type does. If I wanted the square type to implement the rectangle interface I would just need to remove the pointer receivers.

虽然您可能希望这样做,但是在这个示例中,正方形类型不实现矩形接口。它使用的是*square。如果我想让正方形类型实现矩形接口,我只需要删除指针接收器。

type rectangle interface {
    height() int
    width() int
}

type square struct {
    length int
}

func (sq square) width() int {
    return sq.length
}

func (sq square) height() int {
    return sq.length
}

到此这篇关于Go interface 接口的最佳实践的文章就介绍到这了,更多相关Go interface 接口内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • golang基础之Interface接口的使用

    接口是一个或多个方法签名名的集合,定义方式如下 type Interface_Name interface { method_a() string method_b() int .... } 只要某个类型拥有该接口的所有方法签名,就算实现该接口,无需显示声明实现了那个接口,这称为structural Typing package main import "fmt" type USB interface { //定义一个接口:方法的集合 Name() string //Name方法,返回

  • go语言interface接口继承多态示例及定义解析

    目录 1.什么是接口 2.接口定义 3.多态 多态加减计算器 4.接口继承与转换 5.空接口 6.接口转换 7.实现map字典接口 8.interface案例 1.什么是接口 接口就是一种规范与标准,在生活中经常见接口,例如:笔记本电脑的USB接口,可以将任何厂商生产的鼠标与键盘,与电脑进行链接.为什么呢?原因就是,USB接口将规范和标准制定好后,各个生产厂商可以按照该标准生产鼠标和键盘就可以了. 在程序开发中,接口只是规定了要做哪些事情,干什么.具体怎么做,接口是不管的.这和生活中接口的案例也

  • Go 通过结构struct实现接口interface的问题

    目录 一.通过结构(struct) 实现 接口(interface) 二.代码示例 一.通过结构(struct) 实现 接口(interface) 1.在了解iris框架的时候,经常看到有这样去写的使用一个空结构体作为接收器,来调用方法,有点好奇这样做有什么意义. 解释:在 Go 语言中,一个 struct 实现了某个接口里的所有方法,就叫做这个 struct 实现了该接口. 2.空结构体有以下几大特点 A.不占用内存地址. B.地址不变 3.首先我们知道interface定义的是抽象方法,而下

  • Go interface 接口的最佳实践经验分享

    目录 Go语言-Go 接口的最佳实践 什么是Golang中的interface 编写接口的最佳实践 1. 保持interfaces足够小 2. Interfaces Should Have No Knowledge of Satisfying Types 3. 接口不是类 有关接口的更多信息 空的接口 Zero value of an interface 指针上的接口 Go语言-Go 接口的最佳实践 原文连接:https://blog.boot.dev/golang/golang-interfa

  • PHP curl 并发最佳实践代码分享

    本文将探讨两种具体的实现方法, 并对不同的方法做简单的性能对比. 1. 经典cURL并发机制及其存在的问题 经典的cURL实现机制在网上很容易找到, 比如参考PHP在线手册的如下实现方式: 复制代码 代码如下: function classic_curl($urls, $delay) { $queue = curl_multi_init(); $map = array(); foreach ($urls as $url) { // create cURL resources $ch = curl

  • 浅谈Spring Boot 开发REST接口最佳实践

    本文介绍了Spring Boot 开发REST接口最佳实践,分享给大家,具体如下: HTTP动词与SQL命令对应 GET 从服务器获取资源,可一个或者多个,对应SQL命令中的SELECT GET /users 获取服务器上的所有的用户信息 GET /users/ID 获取指定ID的用户信息 POST 在服务器上创建一个新资源,对应SQL命令中的CREATE POST /users 创建一个新的用户 PUT 在服务器上更新一个资源,客户端提供改变后的完整资源,对应SQL命令中的UPDATE PUT

  • java interface 接口的使用好处分析

    本文实例讲述了java  interface 接口的使用优点.分享给大家供大家参考,具体如下: 接口interface 的作用是什么? 假设在以前我们开发了某个业务的实现类Demo1,现在根据需求我们需要重新设计该业务的实现类Demo2且不能影响其它业务的运行. 这时候就需要一个标准,一个针对该业务实现的一个标准接口(standard interface).而所有实现该接口(interface)的类都需要去实现该接口的方法.通过java向上转型实现针对不同的业务有不同类的实现. 注释: 1.in

  • java  interface 接口的使用好处分析

    本文实例讲述了java  interface 接口的使用优点.分享给大家供大家参考,具体如下: 接口interface 的作用是什么? 假设在以前我们开发了某个业务的实现类Demo1,现在根据需求我们需要重新设计该业务的实现类Demo2且不能影响其它业务的运行. 这时候就需要一个标准,一个针对该业务实现的一个标准接口(standard interface).而所有实现该接口(interface)的类都需要去实现该接口的方法.通过java向上转型实现针对不同的业务有不同类的实现. 注释: 1.in

  • webpack配置的最佳实践分享

    本文主要介绍了关于webpack配置的最佳实践,本文分享的实践具有以下的优势: 使用happypack提升打包速度. 使用MD5 hash可以生成文件版本,进行版本控制 在非单页面的系统中支持多个入口的配置 模板中可以利用htmlplugin输出一些配置性的信息 支持devserver,支持本地json数据的mock 一.webpack最佳实践中的需求 1.热加载 2.语法校验 3.js打包 4.模板打包 二.解决方案 1.webpack.config.json var path = requi

  • 分享20个数据库设计的最佳实践

    数据库设计是整个程序的重点之一,为了支持相关程序运行,最佳的数据库设计往往不可能一蹴而就,只能反复探寻并逐步求精,这是一个复杂的过程,也是规划和结构化数据库中的数据对象以及这些数据对象之间关系的过程.下面给出了20个数据库设计最佳实践,当然,所谓最佳,还是要看它是否适合你的程序.一起来了解了解吧. 1.使用明确.统一的标明和列名,例如 School, SchoolCourse, CourceID. 2.数据表名使用单数而不是复数,例如 StudentCourse,而不是StudentCourse

  • 10个微妙的Java编码最佳实践

    这是一个比Josh Bloch的Effective Java规则更精妙的10条Java编码实践的列表.和Josh Bloch的列表容易学习并且关注日常情况相比,这个列表将包含涉及API/SPI设计中不常见的情况,可能有很大影响. 我在编写和维护jOOQ(Java中内部DSL建模的SQL)时遇到过这些.作为一个内部DSL,jOOQ最大限度的挑战了Java的编译器和泛型,把泛型,可变参数和重载结合在一起,Josh Bloch可能不会推荐的这种太宽泛的API. 让我与你分享10个微妙的Java编码最佳

  • XAML: 自定义控件中事件处理的最佳实践方法

    在开发 XAML(WPF/UWP) 应用程序中,有时候,我们需要创建自定义控件 (Custom Control) 来满足实际需求.而在自定义控件中,我们一般会用到一些原生的控件(如 Button.TextBox 等)来辅助以完成自定义控件的功能. 自定义控件并不像用户控件 (User Control) 一样,使用 Code-Behind(UI 与逻辑在一起)技术.相反,它通过把 UI 与逻辑分离而将两者解耦.因此,创建一个自定义控件会产生两个文件,一个是 Generic.xaml,在它里面定义其

  • 构建Vue大型应用的10个最佳实践(小结)

    这些是我构建大型Vue项目得出的最佳实践,这些技巧将帮助你更高效的编码,并且使其更容易维护和协作. 在我今年的自由职业生涯中我有幸开发了一些大型Vue程序.我所说的这些项目使用了大量Vuex stores

随机推荐