当前位置:网站首页>[Effective Go 中文翻译]函数篇
[Effective Go 中文翻译]函数篇
2022-04-23 06:48:00 【凌星An】
Functions
Multiple return values 多个返回值
Go中的函数和方法最不寻常的特点就是可以返回多个变量。这种形式可以改善C编程中一些笨拙的编程习惯,返回错误-1表示EOF ,传递变量地址来修改变量。
在 C 语言中,写入错误由负数错误码表示,不易察觉。在 Go 中,Write 可以返回一个计数和一个错误:设备可能指写入了部分数据 。
os包内的Write 的方法签名为:
func (file *File) Write(b []byte) (n int, err error)
当写入的字节数n!=len(b) 时,会返回一个非nil的错误error ;这是一种非常常见的风格。
这种语法,避免了传递指针来模拟引用参数作为返回值的需要。 这里有一个简单的函数,它从字节切片中的某个位置抓取一个数字,返回该数字和下一个位置。
func nextInt(b []byte, i int) (int, int) {
for ; i < len(b) && !isDigit(b[i]); i++ {
}
x := 0
for ; i < len(b) && isDigit(b[i]); i++ {
x = x*10 + int(b[i]) - '0'
}
return x, i
}
你可以这样来遍历slice中的数据
eg:
for i := 0; i < len(b); {
x, i = nextInt(b, i)
fmt.Println(x)
}
Named result parameters 命名返回值
Go中函数的返回值,可以进行命名,像常规变量和函数参数一样进行使用。函数执行的时候,命名的返回值会被初始化为对应类型的默认值。 当执行到return语句时,当前的命名返回值变量,会作为返回值返回。
这种命名不是强制的,但它可以使代码更加清晰。
上面的nextInt可以改写为:
eg:
func nextInt(b []byte, pos int) (value, nextPos int) {
命名返回值会被初始化,且与简单的return语句关联,这种风格是很简单而且易于理解的。io.ReadFull 中就使用了这种形式。
func ReadFull(r Reader, buf []byte) (n int, err error) {
for len(buf) > 0 && err == nil {
var nr int
nr, err = r.Read(buf)
n += nr
buf = buf[nr:]
}
return
}
Defer
Go中的defer语句 会安排 延迟函数 在函数执行return前进行调用。这是一种不常用但是有效的 解决函数任何情况下退出都要释放申请的资源的方式,
下面是释放锁或者关闭文件的一个经典案例。
eg:
// Contents returns the file's contents as a string.
func Contents(filename string) (string, error) {
f, err := os.Open(filename)
if err != nil {
return "", err
}
defer f.Close() // f.Close will run when we're finished.
var result []byte
buf := make([]byte, 100)
for {
n, err := f.Read(buf[0:])
result = append(result, buf[0:n]...) // append is discussed later.
if err != nil {
if err == io.EOF {
break
}
return "", err // f will be closed if we return here.
}
}
return string(result), nil // f will be closed if we return here.
}
像上面Close那样延迟调用有两个优势: 1.它确保你不会忘记关闭文件,这个错误在增加新的return 时是很容易出现的。 2.在open后使用close,可以是代码更加清晰。
延迟函数的参数 或者是方法的接收者 在执行defer的时候被确定,而不是在函数执行时确定。所以不要担心函数执行时,改变延迟函数的参数。同样,这也意味着一个defer调用可以执行多个延迟函数。
eg:
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
延迟函数是以LIFO(后进先出)的顺序执行的。所以上面的函数返回时打印4 3 2 1 0
演示:
package main
import "fmt"
func fun(){
fmt.Println("fun start")
for i := 0; i < 5; i++ {
defer fmt.Printf("%d ", i)
}
fmt.Println("fun end")
return
}
func main() {
fun()
fmt.Println("main ...")
}
结果:
fun start
fun end
4 3 2 1 0 main …
一个更加合理的例子是trace函数的执行。我们编写了几个简单的路径
eg:
func trace(s string) {
fmt.Println("entering:", s) }
func untrace(s string) {
fmt.Println("leaving:", s) }
// Use them like this:
func a() {
trace("a")
defer untrace("a")
// do something....
}
我们可以利用 执行defer语句时确定延迟函数参数 的特点 编写更好的代码。
eg:
func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func a() {
defer un(trace("a"))
fmt.Println("in a")
}
func b() {
defer un(trace("b"))
fmt.Println("in b")
a()
}
func main() {
b()
}
结果:
entering: b
in b
entering: a
in a
leaving: a
leaving: b
对于一个习惯于其他语言模块化管理资源的程序员而言,defer看起来十分奇怪。但它确实是一种有趣且强大的应用 ,更加准确的描述它基于函数,而不是模块化。我们可以在使用panic和recover中,看到它的另一种可能。
版权声明
本文为[凌星An]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_43519514/article/details/124298654
边栏推荐
- 内网渗透系列:内网隧道之dnscat2
- SAP sto with billing process and configuration
- Complete learning from scratch, machine learning and deep learning, including theory and code implementation, mainly using scikit and mxnet, and some practices (on kaggle)
- 【编程实践/嵌入式比赛】嵌入式比赛学习记录(一):TCP服务器和web界面的建立
- Internal network security attack and defense: a practical guide to penetration testing (8): Authority maintenance analysis and defense
- Intranet penetration series: dns2tcp of Intranet tunnel
- [programming practice / embedded competition] learning record of embedded competition (II): picture streaming based on TCP
- Intranet security attack and defense: a practical guide to penetration testing (6): domain controller security
- Mysql database backup and recovery under Linux (full + incremental)
- Principle of sentinel integrating Nacos to update data dynamically
猜你喜欢

Research on software security based on NLP (I)

Intranet penetration series: dns2tcp of Intranet tunnel

sentinel集成nacos动态更新数据原理

Intranet penetration series: ICMP of Intranet tunnel_ Tran

内网渗透系列:内网隧道之dns2tcp

NLLLoss+log_SoftMax=CE_Loss

Chapter V investment real estate

Cloud computing skills competition -- the first part of openstack private cloud environment

Redis -- why is the string length of string emstr the upper limit of 44 bytes?

输入 “ net start mysql ”,出现 “ 发生系统错误 5。 拒绝访问 ” 。问题详解
随机推荐
云计算技能大赛 -- openstack私有云环境 第二部分
BUUCTF MISC刷题
Intranet penetration series: icmptunnel of Intranet tunnel (Master James Barlow's)
Go语学习笔记 - 数组 | 从零开始Go语言
Feign source code analysis
CTF-MISC总结
Intranet penetration series: ICMP of Intranet tunnel_ Tran
MYSQL——第一章节(数据类型2)
Intranet penetration series: dns2tcp of Intranet tunnel
Ctf-misc learning from start to give up
Reptile learning notes, learning reptile, read this article is enough
内网渗透系列:内网隧道之dns2tcp
内网渗透系列:内网隧道之icmptunnel(jamesbarlow师傅的)
Sto with billing cross company inventory dump return
C problem of marking the position of polygons surrounded by multiple rectangles
《内网安全攻防:渗透测试实战指南》读书笔记(四):权限提升分析及防御
DVWA靶场练习
Solidity IDE Remix中文版使用手册
巨头押注的全屋智能,正在驱动海信、华为、小米们「自我革命」
Link to some good tutorials or notes about network security and record them