如何在源代码中获取变量名称(使用反射)?

时间:2014-07-19 04:17:55

标签: go

我正在尝试构建一个易于使用的模板系统。基本上我只想创建一个包含不同变量(字符串)的切片,然后遍历切片并将标记{{}}替换为实际值。因此,如果变量“name”为onevar,它将在{{onevar}}的模板中查找,并将其替换为变量的实际值。

问题:如何获取变量名称?基本上是源代码中的内容。可能吗 ?我尝试过反思,但似乎无法做到正确。见下文

onevar := "something"
other := "something else"

var msg string
    sa := []string{onevar, other}
    for _, v := range sa {
        vName := reflect.TypeOf(v).Name()
        vName = fmt.Sprintf("{{%s}}", vName)
        msg = strings.Replace(msg, vName, v, -1)
    }

3 个答案:

答案 0 :(得分:2)

你不能做这样的事情。 slive 包含变量但是,因此您无法获取其名称。只需使用地图。

答案 1 :(得分:1)

而不是使用变量名称,您可以使用带有(字符串转换的)指针的切片来实现您的原始目标:

package main

import "fmt"
import "unsafe"
import "strconv"

func castStr(v *string) string {
    return fmt.Sprint(uintptr(unsafe.Pointer(v)))
}

func uncastStr(s string) string {
    p, _ := strconv.ParseInt(s, 10, 64)
    return *((*string)(unsafe.Pointer(uintptr(p))))
}

func main() {
    onevar := "something"
    other := "something else"
    sa := []string{castStr(&onevar), castStr(&other)}

    for _, v := range sa {
        fmt.Printf("{{%s}}\n", v)
        fmt.Printf("%v\n", uncastStr(v))
    }

    //for _, v := range sa {
    //  vName := fmt.Sprintf("{{%s}}", v)
    //  msg = strings.Replace(msg, vName, uncastStr(v) -1)
    //}
}

(在这里看不到使用不安全的问题,因为任何强制转换都不是基于不受控制的内容而且不安全.Pointer仅用于阅读。 注意!:请记住,指针值可能会因程序运行而异。因此,在程序的第二次运行中替换模板{{xxx}}可能会失败。此外:该场景(第二次运行)可能“不安全”,因为可能会评估不相关的内存。)

答案 2 :(得分:0)

这是个好问题。我需要相同的解决方案,但对于vars(我认为这不可能)-对于结构。您可以尝试为此使用结构。

package main

import (
    "fmt"
    "reflect"
)

type Some struct {
    Foo bool
    A   string
    Bar int
    B   string
}

func (structPoint *Some) GetFieldName(fieldPinter interface{}) (name string) {

    val := reflect.ValueOf(structPoint).Elem()
    val2 := reflect.ValueOf(fieldPinter).Elem()

    for i := 0; i < val.NumField(); i++ {
        valueField := val.Field(i)
        if valueField.Addr().Interface() == val2.Addr().Interface() {
            return val.Type().Field(i).Name
        }
    }
    return
}

func main() {
    a := Some{}

    fieldName := a.GetFieldName(&a.Foo)
    fmt.Println(fieldName)

    fieldName = a.GetFieldName(&a.Bar)
    fmt.Println(fieldName)

    //Foo
    //Bar
}

https://play.golang.org/p/0duV6GY2NSG