zoukankan      html  css  js  c++  java
  • Golang的一些学习

    在 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
        	}
        }
    
  • 相关阅读:
    Dubbo架构设计及原理详解
    Zookeeper+Dubbo+SpringMVC环境搭建
    Java 延迟队列使用
    深入理解Spring Redis的使用 (九)、通过Redis 实现 分布式锁 的 BUG,以及和数据库加锁的性能测试
    深入理解Spring Redis的使用 (八)、Spring Redis实现 注解 自动缓存
    深入理解Spring Redis的使用 (七)、Spring Redis 使用 jackson序列化 以及 BaseDao代码
    深入理解Spring Redis的使用 (六)、用Spring Aop 实现注解Dao层的自动Spring Redis缓存
    深入理解Spring Redis的使用 (五)、常见问题汇总
    深入理解Spring Redis的使用 (四)、RedisTemplate执行Redis脚本
    深入理解Spring Redis的使用 (三)、使用RedisTemplate的操作类访问Redis
  • 原文地址:https://www.cnblogs.com/Przz/p/9519112.html
Copyright © 2011-2022 走看看