英文:
How to get the variable name as in the source code (using reflect)
问题
我正在尝试构建一个易于使用的模板系统。基本上,我只想创建一个包含不同变量(字符串)的切片,然后循环遍历该切片,并用实际值替换标记{{}}
。所以,如果变量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)
}
请注意,我只会翻译代码部分,不会回答关于翻译的问题。
英文:
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 "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)
//}
}
(Don'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 "unsafe" 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 (
"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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论