• Go出现panic的场景


    概述

    go中发生panic的场景:
    - 数组/切片越界
    - 空指针调用。比如访问一个 nil 结构体指针的成员
    - 过早关闭 HTTP 响应体
    - 除以 0
    - 向已经关闭的 channel 发送消息
    - 重复关闭 channel
    - 关闭未初始化的 channel
    - 未初始化 map。注意访问 map 不存在的 key 不会 panic,而是返回 map 类型对应的零值,但是不能直接赋值
    - 跨协程的 panic 处理
    - sync 计数为负数。
    - 类型断言不匹配。`var a interface{} = 1; fmt.Println(a.(string))` 会 panic,建议用 `s,ok := a.(string)`

    代码

    package a_panics
    
    import (
        "fmt"
        "math/rand"
        "testing"
        "time"
    )
    
    type Student struct {
        Name string
        Age  int
    }
    
    func TestP0(t *testing.T) {
        // 空指针调用: 访问一个 nil 结构体指针的成员
        var s *Student
        fmt.Println(s.Name)
    }
    
    func TestP1(t *testing.T) {
    
        // 除数为0
        fmt.Println(100 / 0)
    
        // rand.Intn方法:如果里面的参数 <=0 的话,会panic
        rand.Seed(time.Now().UnixNano())
        fmt.Println(rand.Intn(0))
    
        // 数组/切片越界
        lst := []string{"whw", "naruto", "sasuke"}
        fmt.Println(lst[0:22])
    
        // 为初始化map
        var m1 map[string]interface{}
        fmt.Println(m1["name"]) // 直接取值不会panic
        m1["age"] = 22
        /*
            // 下面这样可以
            m1 := make(map[string]interface{}, 0)
            m1["age"] = 22
        */
    
        // 断言类型不匹配
        var a interface{} = 1
        fmt.Println(a.(string))
        /*
            // 建议这样写:
            s,ok := a.(string)
            fmt.Println("ok: ", ok, "s: ", s)
        */
    
    }

    ~~~

    package a_panics
    
    import (
        "fmt"
        "io/ioutil"
        "net/http"
        "testing"
    )
    
    func TestHttpBody(t *testing.T) {
    
        url := "https://www.baidu.com"
        method := "GET"
    
        client := &http.Client{}
        req, err := http.NewRequest(method, url, nil)
    
        if err != nil {
            fmt.Println(err)
            return
        }
    
        res, err := client.Do(req)
        if err != nil {
            fmt.Println(err)
            return
        }
    
        // TODO (不加defer)过早关闭HTTP响应体
        defer res.Body.Close()
    
        body, err := ioutil.ReadAll(res.Body)
        if err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println(string(body))
    }

    ~~~

    package a_panics
    
    import "fmt"
    
    import "testing"
    
    func TestChannel0(t *testing.T) {
    
        //ch := make(chan int)
        // 关闭未初始化的channel
        var ch chan int
        close(ch)
    
    }
    
    func TestChannel1(t *testing.T) {
    
        ch := make(chan int) // no-cached channel
        go func() {
            // 子goroutine中向channel中存放值
            ch <- 1
            close(ch)
        }()
        // 主 goroutine 接收channel的值
        x := <-ch
        fmt.Println("x: ", x)
    
        // TODO // 像已关闭的channel发送消息
        ch <- 2
    }
    
    func TestChannel2(t *testing.T) {
    
        ch := make(chan int) // no-cached channel
        go func() {
            // 子goroutine中向channel中存放值
            ch <- 1
            close(ch)
        }()
        // 主 goroutine 接收channel的值
        x := <-ch
        fmt.Println("x: ", x)
    
        // TODO 重复关闭channel
        close(ch)
    }

    ~~~

    package a_panics
    
    import (
        "fmt"
        "testing"
    )
    
    func test(){
    
        defer func(){
            // 捕获异常
            if err := recover(); err != nil{
                fmt.Println("errFromFunc:test", err)
            }
        }()
    
        var m1 map[string]interface{}
        m1["age"] = 22
    }
    
    func sayHello(){
        fmt.Println("hello!")
    }
    
    func TestP4(t *testing.T){
    
        go test()
        go sayHello()
    
    }
  • 相关阅读:
    MySQL数据库的安装与密码配置
    Java 的设计模式之一装饰者模式
    Java中Eclipse的使用
    Java的学习之路
    Java学习笔记(06)
    Java学习笔记(05)
    Java学习笔记(04)
    mysql出现2003——can't connect to mysql server on localhost(10061)
    抢票难。
    java 的接口起什么作用
  • 原文地址:https://www.cnblogs.com/paulwhw/p/15585467.html
Copyright © 2020-2023  润新知