calldepth,顾名思义就是“调用深度”。首先你要知道什么是“函数栈”。假设有这样的函数间关系 A → B → C... 函数 A 调用了函数 B,函数 B 又调用了函数 C,依次类推……那么在函数 C 内部想要知道到底是谁调用的它(也就是 A),那么就得在栈上往上找 2 层。log 模块的函数栈是 log.Printf → std.Output → runtime.Caller 这样的,所以默认值是 2,就是从 runtime.Caller 往上找 2 层,就能知道 log.Printf 是从哪来的了。为啥要往上找?因为你这是日志模块,你肯定需要知道最终打 log 的那个最上层的调用方到底是谁(就是谁执行了 log.Printf 这行代码),这样才能再日志里输出出来的文件、行号等堆栈信息。如果你不是直接用的 log 模块,而是自己又封装了一层,那 calldepth 就得传 3 了。因为还传 2 只能定位到你封装的那层上,定位不到实际打 log 的那层。依次类推,你每多封装一层,celldepth 就 +1。至于注释里的 PC,是 Program Counter(程序计数器)的缩写。这个需要了解一点计算机组成原理的相关知识。你就知道它实际代表 CPU 当前指令地址就可以了。所谓 “恢复 PC” 就是指定位到当前执行的那句代码上。这个前面已经提到过了。
calldepth,顾名思义就是“调用深度”。
首先你要知道什么是“函数栈”。
假设有这样的函数间关系
A → B → C...
函数 A 调用了函数 B,函数 B 又调用了函数 C,依次类推……那么在函数 C 内部想要知道到底是谁调用的它(也就是 A),那么就得在栈上往上找 2 层。log 模块的函数栈是
log.Printf → std.Output → runtime.Caller
这样的,所以默认值是 2,就是从runtime.Caller
往上找 2 层,就能知道log.Printf
是从哪来的了。为啥要往上找?因为你这是日志模块,你肯定需要知道最终打 log 的那个最上层的调用方到底是谁(就是谁执行了
log.Printf
这行代码),这样才能再日志里输出出来的文件、行号等堆栈信息。如果你不是直接用的 log 模块,而是自己又封装了一层,那 calldepth 就得传 3 了。因为还传 2 只能定位到你封装的那层上,定位不到实际打 log 的那层。
依次类推,你每多封装一层,celldepth 就 +1。
至于注释里的 PC,是 Program Counter(程序计数器)的缩写。
这个需要了解一点计算机组成原理的相关知识。你就知道它实际代表 CPU 当前指令地址就可以了。所谓 “恢复 PC” 就是指定位到当前执行的那句代码上。这个前面已经提到过了。