在 Go 中使用命名返回变量捕获 panic

在下面代码中,如果pressButton发生panic,那么不会执行到return err,导致返回的err是nil。

    func doStuff() error {
var err error
// If there is a panic we need to recover in a deferred func
defer func() {
if r := recover(); r != nil {
err = errors.New("the meeseeks went crazy!")
}
}() pressButton()
return err
}

可以使用命名返回变量解决,即使我们从未触碰到 doStuff 函数的末尾的返回语句,也会立刻返回这个 err 变量。

    func doStuff() (err error) {
// If there is a panic we need to recover in a deferred func
defer func() {
if r := recover(); r != nil {
err = errors.New("the meeseeks went crazy!")
}
}() pressButton()
return err
}

重新切片(slice)

从 slice 中重新切出新 slice 时,新 slice 会引用原 slice 的底层数组,将导致难以预料的内存使用。可以通过拷贝临时 slice 的数据,而不是重新切片来解决:

    func get() (res []byte) {
raw := make([]byte, 10000)
fmt.Println(len(raw), cap(raw), &raw[0]) // 10000 10000 0xc420080000
res = make([]byte, 3)
copy(res, raw[:3])
return
}
func test() {
slice := a[2:3:4]
//可以利用第三个参数控制容量
//如果设置容量和长度相同,可以append时新创建底层数组,不影响原有的
}

类型声明与方法

从一个现有的非 interface 类型创建新类型时,并不会继承原有的方法:

    // 定义 Mutex 的自定义类型
type myMutex sync.Mutex func main() {
var mtx myMutex
mtx.Lock()
mtx.UnLock()
}
//mtx.Lock undefined (type myMutex has no field or method Lock)…

如果你需要使用原类型的方法,可将原类型以匿名字段的形式嵌到你定义的新 struct 中:

    // 类型以字段形式直接嵌入
type myLocker struct {
sync.Mutex
} func main() {
var locker myLocker
locker.Lock()
locker.Unlock()
}

for + 闭包函数

    type field struct {
name string
} func (p *field) print() {
fmt.Println(p.name)
} // 错误示例
func main() {
data := []field{{"one"}, {"two"}, {"three"}}
for _, v := range data {
go v.print()
}
time.Sleep(3 * time.Second)
// 输出 three three three
} // 正确示例
func main() {
data := []field{{"one"}, {"two"}, {"three"}}
for _, v := range data {
v := v
go v.print()
}
time.Sleep(3 * time.Second)
// 输出 one two three
} // 正确示例
func main() {
data := []*field{{"one"}, {"two"}, {"three"}}
for _, v := range data { // 此时迭代值 v 是三个元素值的地址,每次 v 指向的值不同
go v.print()
}
time.Sleep(3 * time.Second)
// 输出 one two three
}

defer函数参数

对 defer 延迟执行的函数,它的参数会在声明时候就会求出具体值,而不是在执行时才求值:

    // 在 defer 函数中参数会提前求值
func main() {
var i = 1
defer fmt.Println("result: ", func() int { return i * 2 }())
i++
}

select default

如果有default子句,case不满足条件时执行该语句。

如果没有default字句,select将阻塞,直到某个case可以运行;Go不会重新对channel或值进行求值。

缓冲通道中,刚好相反,由于元素值的传递是异步的,所以发送操作在成功向通道发送元素值之后就会立即结束(它不会关心是否有接收操作)。

如果使用非缓冲,ret值必须被接收。如果此函数等待超时直接返回nil,会导致Ret这个Chan在模块那边写不进去堵死。

    func (m *friendModule) Gift*****(cmd GiftCmd) *GiftRet {
ctx, cancel := context.WithTimeout(context.Background(), util.ASyncCmdTimeOut)
defer cancel()
cmd.Ret = make(chan GiftRet, 1) ##非缓冲bug
select {
case m.GiftChan <- cmd:
case <-ctx.Done():
logs.Error("friend moduel gift cmdChan is full")
}
select {
case ret := <-cmd.Ret:
return &ret
case <-ctx.Done():
logs.Error("friend moduel gift cmdChan apply <-retChan timeout")
return nil
}
}

Golang的一些学习的更多相关文章

  1. Golang源码学习:调度逻辑(二)main goroutine的创建

    接上一篇继续分析一下runtime.newproc方法. 函数签名 newproc函数的签名为 newproc(siz int32, fn *funcval) siz是传入的参数大小(不是个数):fn ...

  2. Golang之sdl2学习之路(零) -- 环境工具准备

    学习Golang有一段时间了,从毫无头绪到四处乱撞,再到如今静下心来安心学习sdl2也有小半年了. 今晚重构之前的学习代码,发现如果不写该文,可能会在以后回顾这段时间写的代码上花费时间,故以此文做一点 ...

  3. golang 容器的学习与实践

    golang 提供了几个简单的容器供我们使用,本文在介绍几种Golang 容器的基础上,实现一个基于Golang 容器的LRU算法. 容器介绍 Golang 容器位于 container 包下,提供了 ...

  4. [Golang] Gin框架学习笔记

    0x0 Gin简介 1.Gin 是什么? Gin 是一个用 Go (Golang) 编写的 HTTP web 框架. 它是一个类似于 martini 但拥有更好性能的 API 框架, 由于 httpr ...

  5. golang net包学习笔记

    阅读源代码发现在net包中主要实现了ip.tcp.udp.unix等通信方式.它们大致可以分成两大类:其一,ip.udp.unix(DGRAM),这是一些无链接的协议,其二,tcp.unix(STRE ...

  6. golang 要去学习的文档记录

    xrom开发文档地址: http://gobook.io/read/github.com/go-xorm/manual-zh-CN/chapter-10/ golang基础知识: https://ww ...

  7. Golang gin框架学习

    今天开始学习gin框架,在Github上找的示例的go-gin-example, 进度 日期 进展 疑惑 进展 1.30 下拉代码,初步了解gin的介绍.搭建 .mod文件 module原理.使用方法 ...

  8. Golang源码学习:使用gdb调试探究Golang函数调用栈结构

    本文所使用的golang为1.14,gdb为8.1. 一直以来对于函数调用都仅限于函数调用栈这个概念上,但对于其中的详细结构却了解不多.所以用gdb调试一个简单的例子,一探究竟. 函数调用栈的结构(以 ...

  9. Golang源码学习:调度逻辑(一)初始化

    本文所使用的Golang为1.14,dlv为1.4.0. 源代码 package main import "fmt" func main() { fmt.Println(" ...

  10. Golang源码学习:调度逻辑(四)系统调用

    Linux系统调用 概念:系统调用为用户态进程提供了硬件的抽象接口.并且是用户空间访问内核的唯一手段,除异常和陷入外,它们是内核唯一的合法入口.保证系统的安全和稳定. 调用号:在Linux中,每个系统 ...

随机推荐

  1. Codeforces Gym101606 C.Cued In (2017 United Kingdom and Ireland Programming Contest (UKIEPC 2017))

    C Cued In 这个题是打球的.都忘了写的什么了... 代码: 1 #include<iostream> 2 #include<cstring> 3 #include< ...

  2. IDEA连接linux服务器

    idea连接linux(完成了xshell和xftp连接linux的功能,可以直接卸载这俩了..) File->settings->Deployment左侧加号添加 选择传输类型ftp或者 ...

  3. 项目心得——按照指定的日期/时间创建Date对象

    项目心得——按照指定的日期/时间创建Date对象 有时,在做项目中,需要获得指定日期的Date对象,这个指定的日期或者时间可能不是当前的时间.下面讲解两种获取指定日期/时间的Date对象的方法: pa ...

  4. MySql_ procedure

    返回参数示例 下面是一个示例: delimiter //S drop procedure if EXISTS myzrz; CREATE PROCEDURE myzrz(in pin int,out ...

  5. Leetcode总结之Tree

    package Tree; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; imp ...

  6. android权限大全转http://www.cnblogs.com/classic/archive/2011/06/20/2085055.html

    android权限大全转http://www.cnblogs.com/classic/archive/2011/06/20/2085055.html 访问登记属性 android.permission ...

  7. boost exception jam0.exe 异常错误

    在Windows 8 64 bit下执行boost_1_53_0的bootstrap.bat出现了jam0.exe执行错误 搜索网页发现需要修改两处文件: tools/build/v2/engine/ ...

  8. 【翻译自mos文章】当并行事务恢复进程在执行时,禁用并行事务恢复的方法

    当并行事务恢复进程在执行时,禁用并行事务恢复的方法 How to Disable Parallel Transaction Recovery When Parallel Txn Recovery is ...

  9. andrid对不能导入的类,知道类路径怎样使用该类

    andrid对不能导入的类,知道类路径怎样使用该类?使用java的反射机制. 下边是一个样例. MTK平台对Android源生的Telephone接口进行了扩展,加入了一个TelephonyManag ...

  10. C++ 继承与接口 知识点 小结(一)

    [摘要] 要求理解覆盖.重载.隐藏的概念与相互之间的差别.熟记类继承中对象.函数的訪问控制:掌握虚函数.虚函数表.虚函数指针的联系:理解区分虚函数和虚继承在虚方法.虚指针在空间分配上的重点与难点:熟练 ...