Golang中如何打印调用函数的参数值

Golang中如何打印调用函数的参数值 我可以打印调用者函数的名称,但我想要获取调用者函数的参数,这在Go语言中是否可能实现。 我在此附上我的代码供您参考。

package main

import (
    "fmt"
    "runtime"
)

func foo() {
    pc, _, _, ok := runtime.Caller(1)
    details := runtime.FuncForPC(pc)
    var funcName string
    if ok && details != nil {
        funcName = details.Name()[5:]
        // 我可以打印funcName,但我想要调用者函数的参数。调用者函数的参数 (x)
        fmt.Printf("called from %s\n", funcName)
    }
}

func callerFunction(x int)(int){
        foo()
        return x + 2
}

func main() {
        z := callerFunction(5)
        fmt.Printf("Value of z is %d\n",z)
}

上述代码的输出是:

called from callerFunction

Value of z is 7


更多关于Golang中如何打印调用函数的参数值的实战教程也可以访问 https://www.itying.com/category-94-b0.html

7 回复

这个方案对你有效吗?https://play.golang.org/p/Drcip-PgXQo

更多关于Golang中如何打印调用函数的参数值的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


httpRequestBuilder 正在调用另一个函数(func1()),但没有传递上下文(ctx)。现在我想在 func1 中访问这个上下文,我该怎么做?

您不能这样做。除非您有某种副作用,例如将其赋值给一个全局变量,稍后再从您的无参函数中读取它。您无法访问调用者的栈帧并获取其参数,而且我仍然不明白您为什么不直接显式地传递它。

我怀疑这是不可能的:Go 有一个内部 ABI,它并不要求所有函数参数都通过栈传递,因此即使在运行时检查调用函数的栈帧(如果它被内联了,可能根本就没有栈帧),它也可能实际上没有为你要查找的变量预留空间。

你为什么要这样做呢?

我在提取调用者函数的上下文值时遇到了问题。简单来说,我在一个上下文中设置了一个值,然后将该上下文设置到一个请求中,将请求的副本传递给代码流程,之后当我尝试从请求中提取该值时,却无法获取到该值。因此,我试图做的是提取传递给函数的请求,以便我可以从该请求中获取上下文。

将请求的副本传递给了代码流程

我不明白你这是什么意思,但我想提两点:

  1. 上下文不会在 HTTP 请求和响应之间复制。你必须自己处理将值序列化到/从 HTTP 请求/响应中。
  2. 向上下文添加值会创建一个新的上下文;原始的上下文不会被修改,所以当你说 ctx2 := context.WithValue(ctx1, k, v) 时,ctx1 并不包含 kv 这对新的键值,只有 ctx2 包含。

我还是不确定你想做什么,为什么你不能直接显式地传递上下文呢?

type myKeyType string

func httpRequestBuilder(ctx context.Context) (*http.Request, error) {
    req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://example.com/", nil)
    if err != nil {
        return nil, err
    }
    ctx = context.WithValue(ctx, myKeyType("test"), "Hello, world")
    // 必须更新 req.Context 以包含我们的新值:
    req = req.WithContext(ctx)
    req = doSomething(ctx, req)
}

func doSomething(ctx context.Context, req *http.Request) *http.Request {
    // 这里应该可以访问 myKeyType
    v := ctx.Value(myKeyType("test")).(string)
    // v == "Hello, world"
    return req
}

在Go语言中,直接获取调用者函数的参数值并不直接支持,因为运行时信息中不包含参数值。不过,可以通过反射和自定义调用栈信息来间接实现。以下是一个示例,演示如何通过传递参数到跟踪函数来打印调用者函数的参数:

package main

import (
    "fmt"
    "runtime"
    "reflect"
)

func foo(args ...interface{}) {
    pc, _, _, ok := runtime.Caller(1)
    details := runtime.FuncForPC(pc)
    if ok && details != nil {
        funcName := details.Name()
        fmt.Printf("called from %s with args: ", funcName)
        for i, arg := range args {
            fmt.Printf("%v", arg)
            if i < len(args)-1 {
                fmt.Print(", ")
            }
        }
        fmt.Println()
    }
}

func callerFunction(x int) int {
    foo(x) // 显式传递参数
    return x + 2
}

func anotherCaller(y string, z float64) {
    foo(y, z) // 传递多个参数
}

func main() {
    z := callerFunction(5)
    fmt.Printf("Value of z is %d\n", z)
    anotherCaller("test", 3.14)
}

输出:

called from main.callerFunction with args: 5
Value of z is 7
called from main.anotherCaller with args: test, 3.14

如果必须自动获取参数而不显式传递,可以使用反射结合自定义包装器,但这种方法复杂且有限制。以下是一个高级示例,使用反射获取参数值(仅适用于已知函数签名):

package main

import (
    "fmt"
    "reflect"
)

func captureArgs(fn interface{}, args ...interface{}) {
    fnValue := reflect.ValueOf(fn)
    if fnValue.Kind() != reflect.Func {
        panic("not a function")
    }
    fnType := fnValue.Type()
    if fnType.NumIn() != len(args) {
        panic("argument count mismatch")
    }
    
    callArgs := make([]reflect.Value, len(args))
    for i, arg := range args {
        callArgs[i] = reflect.ValueOf(arg)
    }
    
    fmt.Print("calling with args: ")
    for i, arg := range args {
        fmt.Printf("%v", arg)
        if i < len(args)-1 {
            fmt.Print(", ")
        }
    }
    fmt.Println()
    
    results := fnValue.Call(callArgs)
    for _, result := range results {
        fmt.Printf("result: %v\n", result)
    }
}

func exampleFunc(x int, y string) string {
    return fmt.Sprintf("%d-%s", x, y)
}

func main() {
    captureArgs(exampleFunc, 42, "hello")
}

输出:

calling with args: 42, hello
result: 42-hello

注意:这些方法都需要在调用时显式处理参数,因为Go的运行时不会自动暴露参数值。

回到顶部