• 编程陷阱:切片追加


    编程陷阱:切片追加

    • 之前在做项目的过程中,切片追加使用的非常的多,用多了肯定就会莫名其妙的出现很多的bug,今天就带大家一起看看这些bug。

    问题:

    根据bug我来还原代码,大家看一看有没有问题

    题目一:

    函数Validation()用于一些合法性检查,每遇到一个错误,就生成一个新的error并追加到切片errs中,最后返回包含所有错误信息的切片。
    为了简单起见,假定函数发现了三个错误,如下所示:

    func Validation() []error {
        var errs []error
    
        append(errs, errors.New("error 1"))
        append(errs, errors.New("error 2"))
        append(errs, errors.New("error 3"))
    
        return errs
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    请问函数Validation()有什么问题?

    题目二:

    函数ValidateName()用于检查某个名字是否合法,如果不为空则认为合法,否则返回一个error。类似的,还可以有很多检查项,比如检查性别、年龄等,我们统称为子检查项。函数Validations()用于收集所有子检查项的错误信息,将错误信息汇总到一个切片中返回。

    请问函数Validations()有什么问题?

    func ValidateName(name string) error {
        if name != "" {
            return nil
        }
    
        return errors.New("empty name")
    }
    
    func Validations(name string) []error {
        var errs []error
    
        errs = append(errs, ValidateName(name))
    
        return errs
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    陷阱及解决

    题目一:

    陷阱: append 会改变切片的地址

    append的本质是向切片中追加数据,而随着切片中元素逐渐增加,当切片底层的数组将满时,切片会发生扩容,扩容会导致产生一个新的切片(拥有容量更大的底层数组),更多关于切片的信息,请查阅切片相关章节。

    append每个追加元素,都有可能触发切片扩容,也即有可能返回一个新的切片,这也是append函数声明中返回值为切片的原因。实际使用中应该总是接收该返回值。

    上述题目一中,由于初始切片长度为0,所以实际上每次append都会产生一个新的切片并迅速抛弃(被gc回收)。
    原始切片并没有任何改变。需要特别说明的是,不管初始切片长度为多少,不接收append返回都是有极大风险的。

    题目二:

    陷阱:append 可以追加nil值

    向切片中追加一个nil值是完全不会报错的,如下代码所示:

    slice := append(slice, nil)
    
    • 1

    经过追加后,slice的长度递增1。

    实际上nil是一个预定义的值,即空值,所以完全有理由向切片中追加。

    上述题目二中,就是典型的向切片中追加nil(当名字为空时)的问题。单纯从技术上讲是没有问题,但在题目二场景中就有很大的问题。

    题目中函数用于收集所有错误信息,没有错误就不应该追加到切片中。因后,后续极有可能会根据切片的长度来判断是否有错误发生,比如:

    func foo() {
        errs := Validations("")
    
        if len(errs) > 0 {
            println(errs)
            os.Exit(1)
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    如果向切片中追加一个nil元素,那么切片长度则不再为0,程序很可能因此而退出,更糟糕的是,这样的切片是没有内容会打印出来的,这无疑又增加了定位难度。

  • 相关阅读:
    关于滑块验证码的问题
    顺应潮流,解放双手,让ChatGPT不废话直接帮忙编写可融入业务可运行的程序代码(Python3.10实现)
    【计算机基础知识9】前端设计模式与常见类型
    联邦学习中的差分隐私与同态加密
    物理服务器安装CentOS 7操作系统
    C++ Primer第5版 习题答案 第十二章
    大坝安全监测解决方案
    【PHP】php中JSON或数组到formData的键值对转换
    REST会消失吗?事件驱动架构如何搭建?
    洛谷 P1909 [NOIP2016 普及组] 买铅笔
  • 原文地址:https://blog.csdn.net/weixin_51261234/article/details/126436111