译|What “accept interfaces, return structs” means in Go

简介: accept interfaces, return structs

“接受接口、返回结构” 的一般原则,我在前一篇文章中写到,也多次在代码评审时向同事介绍,但经常遇到“为什么”的疑问。特别是因为这不是一条硬性规定。该想法的关键在于保持灵活性的同时避免预先抽象,并理解何时改变它。

预先抽象使系统变得复杂

计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决,当然,间接过多的问题除外 - David J. Wheeler

软件工程师喜欢抽象。就我个人而言,从未见过编写代码比创建抽象更投入的同事。Go 中,接口抽象脱离了结构,该间接层甚至没有最低层次的嵌入复杂性。遵循软件设计 您不会用到它 的哲学,在需要之前制造这种复杂性毫无意义。函数调用返回接口的一个常见原因是让用户专注于函数开放的 API。因为有隐式接口,Go 不需要这样做。结构的 public function iu 就是其 API。

总是当 真正 需要时 [抽象],不要当 预见 需要时 [抽象]。

某些语言要求你预见未来需要的每个接口。隐式接口的一大优点是,它们允许事后进行优雅的抽象,而无需预先进行抽象。

因人而异的“需要”

当真正需要时

如何定义何时需要抽象?对于返回类型,这很容易。你是编写该函数的人,因此您确切知道何时需要将返回值抽象。

对于函数输入,需求不在你的控制范围之内。你可能认为 database struct 就足够了,但用户可能需要用其他东西装饰它。就算不是不可能,预测每个人使用你的函数的状态也是很困难的。能够精确控制输出,但无法预测用户输入。相比对输出的抽象化,这种不平衡造成了对输入的抽象化更强烈的偏重。

去除不必要的代码细节

简化的另一方面是去除不必要的细节。函数就像烹饪食谱:给定输入,就会得到一个蛋糕!没有食谱会列出不需要的配料。类似地,函数也不应该列出不需要的输入。你如何看以下函数?

func addNumbers(a int, b int, s string) int { 
    return a + b 
}

对于大多数程序员来说,很明显,参数 s 不恰当。当参数是结构时,却不太明显。

type Database struct{ } 
func (d *Database) AddUser(s string) {...} 
func (d *Database) RemoveUser(s string) {...}
func NewUser(d *Database, firstName string, lastName string) { 
    d.AddUser(firstName + lastName) 
}

就像配料太多的食谱一样,NewUser 接收一个可以做太多事情的 Database 对象。它只需要 AddUser,但接收的参数还有 RemoveUser。使用接口创建的函数,可以只依赖于必需。

type DatabaseWriter interface { 
    AddUser(string) 
} 
func NewUser(d DatabaseWriter, firstName string, lastName string) { 
    d.AddUser(firstName + lastName) 
}

Dave Cheney 在描述 接口隔离原则 时 写到了这一点。他还描述了限制输入的其他优点,值得一读。让人理解这个想法的总目标是:

结果同时是一个函数,它的要求是最具体的——它只需要一个可写的东西——并且它的函数是最通用的

我只想补充一点,上面的函数 addNumber 显然不应该有参数字符串 s,函数 NewUser 理想情况下不需要可以删除用户的 database。

总结原因并审查例外

主要原因如下:

  • 去除不需要的抽象
  • 用户对函数输入需求是模糊的
  • 简化函数输入

以上原因还允许我们定义规则的例外情况。例如,如果函数需要返回多种类型,那么显然返回需要定义为接口。类似地,如果函数是私有的,那么函数输入便并不模糊,因为你可以控制它,所以倾向于非预先抽象。对于第三条规则,go 没有办法抽象出 struct 成员的值。因此,如果你的函数需要访问结构体成员(而不仅仅是结构体上的函数),那么您将被迫直接接受结构体。

原文:What “accept interfaces, return structs” means in Go

本文作者 : cyningsun

本文地址 : https://www.cyningsun.com/08-08-2021/go-accept-interfaces-return-structs.html

版权声明 :本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0 CN 许可协议。转载请注明出处!

目录
相关文章
多返回值(Multiple Return Values)- 《Go语言实战指南》
Go 语言支持函数返回多个值,这一特性在实际开发中非常常见,尤其用于错误处理。本文介绍了多返回值的基本语法、用于错误处理的方式、返回值命名、忽略不需要的返回值以及实际应用场景。通过计算商和余数、文件操作、网络响应等示例,展示了多返回值的灵活性。最后总结了使用建议,包括搭配 `error` 实现显式错误控制、命名返回值提升可读性以及用 `_` 忽略无用值等技巧。
464 19
|
编译器 Go
Go 语言怎么解决编译器错误“err is shadowed during return”?
Go 语言怎么解决编译器错误“err is shadowed during return”?
320 0
|
Go PHP
【GO】panic: reflect.Value.Interface: cannot return value obtained from unexported field or method
【GO】panic: reflect.Value.Interface: cannot return value obtained from unexported field or method
785 0
【GO】panic: reflect.Value.Interface: cannot return value obtained from unexported field or method
|
Go
learn go return fuction
package main // 参考文章: // https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/06.
701 0
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
11月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
508 2
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
768 1
|
开发框架 JSON 中间件
Go语言Web开发框架实践:路由、中间件、参数校验
Gin框架以其极简风格、强大路由管理、灵活中间件机制及参数绑定校验系统著称。本文详解其核心功能:1) 路由管理,支持分组与路径参数;2) 中间件机制,实现全局与局部控制;3) 参数绑定,涵盖多种来源;4) 结构体绑定与字段校验,确保数据合法性;5) 自定义校验器扩展功能;6) 统一错误处理提升用户体验。Gin以清晰模块化、流程可控及自动化校验等优势,成为开发者的优选工具。
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。
|
开发框架 JSON 中间件
Go语言Web开发框架实践:使用 Gin 快速构建 Web 服务
Gin 是一个高效、轻量级的 Go 语言 Web 框架,支持中间件机制,非常适合开发 RESTful API。本文从安装到进阶技巧全面解析 Gin 的使用:快速入门示例(Hello Gin)、定义 RESTful 用户服务(增删改查接口实现),以及推荐实践如参数校验、中间件和路由分组等。通过对比标准库 `net/http`,Gin 提供更简洁灵活的开发体验。此外,还推荐了 GORM、Viper、Zap 等配合使用的工具库,助力高效开发。

热门文章

最新文章