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

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM