91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何在Go的函數中得到調用者的函數名

發布時間:2021-09-13 23:13:58 來源:億速云 閱讀:139 作者:chen 欄目:web開發

這篇文章主要講解了“如何在Go的函數中得到調用者的函數名”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“如何在Go的函數中得到調用者的函數名”吧!

func Foo() {     fmt.Println("誰在調用我?")     bar() } func Bar() {     fmt.Println("誰又在調用我?") }

首先打印函數本身的名稱

最簡單的方式就是硬編碼。 因為在編譯之前,我們肯定知道打印的時候所在哪個函數,但是更好的方式是編寫一個通用的函數,比如下面的例子:

package main import (     "fmt"     "runtime" ) func main() {     Foo() } func Foo() {     fmt.Printf("我是 %s, 誰在調用我?\n", printMyName())     Bar() } func Bar() {     fmt.Printf("我是 %s, 誰又在調用我?\n", printMyName()) } func printMyName() string {     pc, _, _, _ := runtime.Caller(1)     return runtime.FuncForPC(pc).Name() }

輸出結果:

我是 main.Foo, 誰在調用我? 我是 main.Bar, 誰又在調用我?

可以看到函數在被調用的時候,printMyName把函數本身的名字打印出來了,注意這里Caller的參數是1,  因為我們將業務代碼封裝成了一個函數。

首先打印函數調用者的名稱

將上面的代碼修改一下,增加一個新的printCallerName的函數,可以打印調用者的名稱。

func main() {     Foo() } func Foo() {     fmt.Printf("我是 %s, %s 在調用我!\n", printMyName(), printCallerName())     Bar() } func Bar() {     fmt.Printf("我是 %s, %s 又在調用我!\n", printMyName(), printCallerName()) } func printMyName() string {     pc, _, _, _ := runtime.Caller(1)     return runtime.FuncForPC(pc).Name() } func printCallerName() string {     pc, _, _, _ := runtime.Caller(2)     return runtime.FuncForPC(pc).Name() }

相關函數介紹

你可以通過runtime.Caller、runtime.Callers、runtime.FuncForPC等函數更詳細的跟蹤函數的調用堆棧。

1、func Caller(skip int) (pc uintptr, file string, line int, ok bool)

Caller可以返回函數調用棧的某一層的程序計數器、文件信息、行號。

0 代表當前函數,也是調用runtime.Caller的函數。1 代表上一層調用者,以此類推。

2、func Callers(skip int, pc []uintptr) int

Callers用來返回調用站的程序計數器, 放到一個uintptr中。

0 代表 Callers 本身,這和上面的Caller的參數的意義不一樣,歷史原因造成的。 1 才對應這上面的 0。

比如在上面的例子中增加一個trace函數,被函數Bar調用。

&hellip;&hellip; func Bar() {     fmt.Printf("我是 %s, %s 又在調用我!\n", printMyName(), printCallerName())     trace() } func trace() {     pc := make([]uintptr, 10) // at least 1 entry needed     n := runtime.Callers(0, pc)     for i := 0; i < n; i++ {         f := runtime.FuncForPC(pc[i])         file, line := f.FileLine(pc[i])         fmt.Printf("%s:%d %s\n", file, line, f.Name())     } }

輸出結果可以看到這個goroutine的整個棧都打印出來了:

/usr/local/go/src/runtime/extern.go:218 runtime.Callers /Users/yuepan/go/src/git.intra.weibo.com/platform/tool/g/main.go:34 main.trace /Users/yuepan/go/src/git.intra.weibo.com/platform/tool/g/main.go:20 main.Bar /Users/yuepan/go/src/git.intra.weibo.com/platform/tool/g/main.go:15 main.Foo /Users/yuepan/go/src/git.intra.weibo.com/platform/tool/g/main.go:10 main.main /usr/local/go/src/runtime/proc.go:210 runtime.main /usr/local/go/src/runtime/asm_amd64.s:1334 runtime.goexit

3、func CallersFrames(callers []uintptr) *Frames

上面的Callers只是或者棧的程序計數器,如果想獲得整個棧的信息,可以使用CallersFrames函數,省去遍歷調用FuncForPC。

上面的trace函數可以更改為下面的方式:

func trace2() {     pc := make([]uintptr, 10) // at least 1 entry needed     n := runtime.Callers(0, pc)     frames := runtime.CallersFrames(pc[:n])     for {         frame, more := frames.Next()         fmt.Printf("%s:%d %s\n", frame.File, frame.Line, frame.Function)         if !more {             break         }     } }

4、func FuncForPC(pc uintptr) *Func

FuncForPC 是一個有趣的函數, 它可以把程序計數器地址對應的函數的信息獲取出來。如果因為內聯程序計數器對應多個函數,它返回最外面的函數。

它的返回值是一個*Func類型的值,通過*Func可以獲得函數地址、文件行、函數名等信息。

除了上面獲取程序計數器的方式,也可以通過反射的方式獲取函數的地址:

runtime.FuncForPC(reflect.ValueOf(foo).Pointer()).Name()

5、獲取程序堆棧

在程序panic的時候,一般會自動把堆棧打出來,如果你想在程序中獲取堆棧信息,可以通過debug.PrintStack()打印出來。比如你在程序中遇到一個Error,但是不期望程序panic,只是想把堆棧信息打印出來以便跟蹤調試,你可以使用debug.PrintStack()。

抑或,你自己讀取堆棧信息,自己處理和打印:

func DumpStacks() {     buf := make([]byte, 16384)     buf = buf[:runtime.Stack(buf, true)]     fmt.Printf("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf) }

參考 調試利器:dump goroutine 的 stacktrace。

利用堆棧信息還可以獲取goroutine的id, 參考: 再談談獲取 goroutine id 的方法

func GoID() int {     var buf [64]byte     n := runtime.Stack(buf[:], false)     idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0]     id, err := strconv.Atoi(idField)     if err != nil {         panic(fmt.Sprintf("cannot get goroutine id: %v", err))     }     return id }

感謝各位的閱讀,以上就是“如何在Go的函數中得到調用者的函數名”的內容了,經過本文的學習后,相信大家對如何在Go的函數中得到調用者的函數名這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

go
AI

南靖县| 博乐市| 博野县| 深州市| 榆中县| 岑溪市| 琼中| 博乐市| 石河子市| 博湖县| 新乐市| 石景山区| 密云县| 伊宁市| 桂平市| 鄄城县| 抚远县| 乌拉特前旗| 商南县| 漳平市| 敦化市| 本溪| 萨迦县| 凤城市| 绵阳市| 秀山| 太仆寺旗| 遂宁市| 宜兰市| 深州市| 炎陵县| 平果县| 博爱县| 佛山市| 老河口市| 钦州市| 辰溪县| 廉江市| 林州市| 海门市| 阿巴嘎旗|