Go中runtime.Caller的使用
Go中runtime.Caller的使用
下面介紹Go runtime.Caller使用
runtime.Caller
函數(shù)定義func runtime.Caller(skip int) (pc uintptr, file string, line int, ok bool)
作用
獲取函數(shù)Caller
的調(diào)用信息
參數(shù)skip=0時(shí)
: 返回調(diào)用Caller的函數(shù)A的pc(program counter)(A即runtime.Caller代碼當(dāng)前所在函數(shù))、所在文件名以及Caller在函數(shù)A中的行數(shù)skip=1時(shí)
: 返回調(diào)用函數(shù)A的函數(shù)B的pc、所在文件名以及函數(shù)A在函數(shù)B中的行數(shù);以此類推
pc
: 程序計(jì)數(shù)器,指向下一條將要取指的指令地址file
: pc對(duì)應(yīng)的函數(shù)所在文件路徑line
: 被調(diào)用方在pc對(duì)應(yīng)的函數(shù)中的行數(shù)
示例:
/Users/go/src/liyouming/golang-trick/40-clean-code-controll-flow/util/util.go
package util import ( "bytes" "fmt" "runtime" ) func CallerTest() { for i := 0; i <= 4; i++ { pc, file, line, ok := runtime.Caller(i) if ok { fmt.Printf("當(dāng)i:=%d時(shí):\n調(diào)用者的pc:%v\n調(diào)用者的函數(shù)名:%s\n"+ "調(diào)用者所在file:%s\n被調(diào)用者在調(diào)用者中的line:%d\n", i, pc, runtime.FuncForPC(pc).Name(), file, line) fmt.Println(string(bytes.Repeat([]byte("*"), 10))) } } }
main.go
package main import ( "golang-trick/40-clean-code-controll-flow/util" ) func main() { util.CallerTest() }
運(yùn)行結(jié)果如下:
當(dāng)i:=0時(shí):
調(diào)用者的pc:17363077
調(diào)用者的函數(shù)名:golang-trick/40-clean-code-controll-flow/util.CallerTest
調(diào)用者所在file:/Users/go/src/liyouming/golang-trick/40-clean-code-controll-flow/util/util.go
被調(diào)用者在調(diào)用者中的line:11
**********
當(dāng)i:=1時(shí):
調(diào)用者的pc:17363702
調(diào)用者的函數(shù)名:main.main
調(diào)用者所在file:/Users/go/src/liyouming/golang-trick/40-clean-code-controll-flow/main.go
被調(diào)用者在調(diào)用者中的line:8
**********
當(dāng)i:=2時(shí):
調(diào)用者的pc:16987729
調(diào)用者的函數(shù)名:runtime.main
調(diào)用者所在file:/usr/local/opt/go/libexec/src/runtime/proc.go
被調(diào)用者在調(diào)用者中的line:250
**********
當(dāng)i:=3時(shí):
調(diào)用者的pc:17158656
調(diào)用者的函數(shù)名:runtime.goexit
調(diào)用者所在file:/usr/local/opt/go/libexec/src/runtime/asm_amd64.s
被調(diào)用者在調(diào)用者中的line:1594
**********
補(bǔ)充:
Go學(xué)習(xí)——runtime.Caller()函數(shù)
函數(shù):
func Caller(skip int) (pc uintptr, file string, line int, ok bool)
Caller()報(bào)告當(dāng)前go程調(diào)用棧所執(zhí)行的函數(shù)的文件和行號(hào)信息。
參數(shù)解釋:
skip
:
上溯的棧幀數(shù),0表示Caller的調(diào)用者(Caller所在的調(diào)用棧)(0-當(dāng)前函數(shù),1-上一層函數(shù),…)。
pc
:
調(diào)用棧標(biāo)識(shí)符
file
:
文件路徑
line
:
該調(diào)用在文件中的行號(hào)
ok
:
如果無(wú)法獲得信息,ok會(huì)被設(shè)為false
例子:
可能看了上面的解釋,對(duì)于skip
參數(shù)依然很迷惑,那我們來(lái)看個(gè)例子:
此時(shí)的項(xiàng)目目錄結(jié)構(gòu):
blog/ ├── conf /... ├── main.go ├── middleware /... ├── models /... ├── pkg │ ├── e /... │ ├── logging │ │ ├── file.go │ │ └── log.go │ ├── setting /... │ └── util /... ├── routers │ ├── api │ │ ├── auth.go │ │ └── v1 │ │ ├── article.go │ │ └── tag.go │ └── router.go ├── runtime
就拿 blog/routers/api/v1/article.go
當(dāng)例子,在這個(gè)文件中GetArticle()
中用到了logging.Info()
:
// followJianYuStudyGo/routers/api/v1/article.go func GetArticle(c *gin.Context) { ... } else { for _, err := range valid.Errors { logging.Info(err.Key, err.Message) // article.go:122 上溯棧幀數(shù)skip = 2 } } ... } // followJianYuStudyGo/pkg/logging/log.go func Info(v ...interface{}) { setPrefix(INFO) // log.go:67 上溯棧幀數(shù)skip = 1 logger.Println(v) } func setPrefix(level Level) { _, file, line, ok := runtime.Caller(DefaultCallerDepth) // log.go:50 上溯棧幀數(shù)skip = 0 .... }
如果我們的skip
:
- 為0:
代表上溯的棧幀數(shù)為0,返回的file
就是調(diào)用Caller()
的位置:
[INFO][log.go:50]2022/04/29 21:07:11 [created_by 創(chuàng)建人不可以為空]
- 為1:
代表上溯的棧幀數(shù)為1,返回的file
就是調(diào)用Caller()
的上一層位置:
[INFO][log.go:67]2022/04/29 21:25:57 [state 狀態(tài)只允許為0或1]
- 為2:
代表上溯的棧幀數(shù)為2,返回的file
就是調(diào)用Caller()
的上一層的上一層位置:
[INFO][article.go:122]2022/04/29 20:52:23 [state 狀態(tài)只允許為0或1]
重點(diǎn):
因?yàn)槲覀冊(cè)?code>logging包里的log.go
文件封裝了Info()、Debug()、Warn()、....
函數(shù),其他地方調(diào)用的都是這種封裝好的函數(shù),所以如果我們打印日志的時(shí)候,想要獲取使用了logging.Info()
的位置,runtime.Caller(skip int)
的skip是要設(shè)置為2的(原因見skip=2的部分)?。。?!
到此這篇關(guān)于Go中runtime.Caller的使用的文章就介紹到這了,更多相關(guān)Go runtime.Caller使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語(yǔ)言HTTPServer開發(fā)的六種方式小結(jié)
Golang的Server開發(fā)顯得非常簡(jiǎn)單,有很多種方式,本文就介紹了Go語(yǔ)言HTTPServer開發(fā)的六種方式,具有一定的參考價(jià)值,感興趣的可以了解一下2021-11-11一文帶你搞懂Golang依賴注入的設(shè)計(jì)與實(shí)現(xiàn)
在現(xiàn)代的 web 框架里面,基本都有實(shí)現(xiàn)了依賴注入的功能,可以讓我們很方便地對(duì)應(yīng)用的依賴進(jìn)行管理。今天我們來(lái)看看 go 里面實(shí)現(xiàn)依賴注入的一種方式,感興趣的可以了解一下2023-01-01Go的os/exec執(zhí)行超時(shí)導(dǎo)致程序死機(jī)的解決方案
這篇文章主要介紹了Go的os/exec執(zhí)行超時(shí)導(dǎo)致程序死機(jī)的幾種解決方案,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-04-04go實(shí)現(xiàn)文件的創(chuàng)建、刪除與讀取示例代碼
這篇文章主要給大家介紹了關(guān)于go如何實(shí)現(xiàn)文件的創(chuàng)建、刪除與讀取的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧2019-02-02Go語(yǔ)言Goroutines?泄漏場(chǎng)景與防治解決分析
這篇文章主要為大家介紹了Go語(yǔ)言Goroutines?泄漏場(chǎng)景與防治解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Golang操作MySql數(shù)據(jù)庫(kù)的完整步驟記錄
這篇文章主要給大家介紹了關(guān)于Golang操作MySql數(shù)據(jù)庫(kù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11