如何通过反射获取源代码中的变量名?

huangapple go评论149阅读模式
英文:

How to get the variable name as in the source code (using reflect)

问题

我正在尝试构建一个易于使用的模板系统。基本上,我只想创建一个包含不同变量(字符串)的切片,然后循环遍历该切片,并用实际值替换标记{{}}。所以,如果变量nameonevar,它将在模板中查找{{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)
}

请注意,我只会翻译代码部分,不会回答关于翻译的问题。

英文:

I'm trying to build an easy to use templating system. Basically I just want to create a slice with different variables ( strings ) and then loop through the slice and replace the markup {{}} with the actual values. So if the variable 'name' is onevar it will look in the template for {{onevar}} and replace that with the actual value of the variable .

Question: how do I get the variable name? Basically what's in the source code. Is it possible ? I've tried something with reflect but seems I couldn't get it right. See belowg

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)
	}

答案1

得分: 3

你不能这样做。切片(slice)中包含的是变量的值,而不是变量本身的名称,所以你无法获取它们的名称。你可以使用一个映射(map)来解决这个问题。

英文:

You cannot do such stuff. The slice does not contain the variables but their values, so you cannot get their name. Just use a map.

答案2

得分: 2

而不是使用变量名,你可以使用一个切片,其中包含(转换为字符串的)指向变量的指针,以达到你的原始目的:

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)
    //}
}

在这里使用unsafe没有问题因为任何类型转换都不是基于不受控制的内容并且unsafe.Pointer仅用于读取
注意请记住指针值可能在程序运行之间变化因此在程序的第二次运行中替换模板{{xxx}}可能会失败此外该场景第二次运行可能是不安全的”,因为可能会访问不相关的内存。)

<details>
<summary>英文:</summary>

instead of working with the variable names, you might work with a slice with (string converted) pointers to the variables to reach your original aim:

    package main

	import &quot;fmt&quot;
	import &quot;unsafe&quot;
	import &quot;strconv&quot;

	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 := &quot;something&quot;
		other := &quot;something else&quot;
		sa := []string{castStr(&amp;onevar), castStr(&amp;other)}

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

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

(Don&#39;t see a problem working with unsafe here because any casting is not being based of uncontrolled content and unsafe.Pointer is only used for reading. 
Attention!: Have in mind that pointer-values might vary between program runs. Thus, replacing the templates {{xxx}} in a second run of the program might fail. Moreover: that scenario (second run) might be &quot;unsafe&quot; since unrelated memory might be assessed.) 


</details>



# 答案3
**得分**: -1

这是一个很好的问题我需要相同的解决方案但不是针对变量我认为这是不可能的),而是针对结构体你可以尝试使用结构体来实现

```golang
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

英文:

Its good question. I need same solution, but not for vars (i think it`s not possible) - for structs. You can try use structures for this.

package main

import (
	&quot;fmt&quot;
	&quot;reflect&quot;
)

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 &lt; 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(&amp;a.Foo)
	fmt.Println(fieldName)

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

	//Foo
	//Bar
}

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

huangapple
  • 本文由 发表于 2014年7月19日 12:17:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/24836696.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定