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()

}

 

posted on 2021-11-21 19:07  江湖乄夜雨  阅读(1357)  评论(0编辑  收藏  举报