
runtime.caller是go标准库runtime包中的一个函数,其主要作用是报告调用者的文件和行号信息。其函数签名如下:
func Caller(skip int) (pc uintptr, file string, line int, ok bool)
参数说明:
最常见的用法是获取runtime.Caller被调用时的文件和行号信息。
package main
import (
"fmt"
"runtime"
)
func main() {
// skip = 0 获取 Caller 函数被调用时的位置
pc, file, line, ok := runtime.Caller(0)
if !ok {
fmt.Println("无法获取调用信息")
return
}
fmt.Printf("当前文件: %s, 行号: %d\n", file, line)
// 可以通过 runtime.FuncForPC(pc).Name() 获取函数名称
fn := runtime.FuncForPC(pc)
if fn != nil {
fmt.Printf("当前函数: %s\n", fn.Name())
}
}运行上述代码,将输出main函数中runtime.Caller(0)所在的文件路径、行号以及函数名。
runtime.Caller的强大之处在于其skip参数,可以用于追溯调用栈。这在实现自定义日志系统、错误报告或调试工具时非常有用。
立即学习“go语言免费学习笔记(深入)”;
考虑以下场景,我们希望在一个辅助函数中记录调用它的上层函数的信息:
package main
import (
"fmt"
"log"
"runtime"
"strings"
)
// logWithLocation 演示如何使用 runtime.Caller 为日志添加文件和行号信息。
// skip = 1,因为我们想要的是调用 logWithLocation 的函数的位置,而不是 logWithLocation 自身。
func logWithLocation(msg string) {
pc, file, line, ok := runtime.Caller(1) // 跳过 logWithLocation 自身
if !ok {
file = "???"
line = 0
}
funcName := "???"
fn := runtime.FuncForPC(pc)
if fn != nil {
funcName = fn.Name()
}
// 截取文件路径,只保留文件名
shortFile := file
lastSlash := strings.LastIndex(file, "/")
if lastSlash != -1 {
shortFile = file[lastSlash+1:]
}
log.Printf("[%s:%d] %s: %s", shortFile, line, funcName, msg)
}
func firstCall() {
secondCall()
}
func secondCall() {
thirdCall()
}
func thirdCall() {
fmt.Println("\n--- 演示 runtime.Caller 不同 skip 值 ---")
// Caller(0) 获取 thirdCall 内部的调用位置
pc0, file0, line0, ok0 := runtime.Caller(0)
if ok0 {
fmt.Printf("Caller(0) (当前函数): %s:%d %s\n", file0, line0, runtime.FuncForPC(pc0).Name())
}
// Caller(1) 获取 secondCall 的调用位置
pc1, file1, line1, ok1 := runtime.Caller(1)
if ok1 {
fmt.Printf("Caller(1) (thirdCall 的调用者): %s:%d %s\n", file1, line1, runtime.FuncForPC(pc1).Name())
}
// Caller(2) 获取 firstCall 的调用位置
pc2, file2, line2, ok2 := runtime.Caller(2)
if ok2 {
fmt.Printf("Caller(2) (secondCall 的调用者): %s:%d %s\n", file2, line2, runtime.FuncForPC(pc2).Name())
}
// Caller(3) 获取 main 函数的调用位置
pc3, file3, line3, ok3 := runtime.Caller(3)
if ok3 {
fmt.Printf("Caller(3) (firstCall 的调用者): %s:%d %s\n", file3, line3, runtime.FuncForPC(pc3).Name())
}
fmt.Println("\n--- 演示 logWithLocation 辅助函数 ---")
logWithLocation("这是一条来自 thirdCall 的消息。")
}
func main() {
firstCall()
logWithLocation("这是一条来自 main 函数的消息。")
}运行上述代码,你将看到runtime.Caller如何根据skip值准确地报告不同层级的调用者信息,以及logWithLocation函数如何利用skip=1来记录其调用者的文件和行号。
runtime.Caller是Go语言中一个强大且实用的函数,它为开发者提供了在运行时获取代码位置信息的能力。通过灵活运用其skip参数,我们可以轻松地实现日志增强、错误追踪等高级功能,极大地提升了Go程序的调试和可维护性。理解并掌握runtime.Caller的用法,是Go语言开发者工具箱中的一项重要技能。
以上就是Go语言中获取源文件及行号的方法:深入解析 runtime.Caller的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号