Golang中如何将变量名转换为字符串名

Golang中如何将变量名转换为字符串名 我正在为一个有些复杂的项目实现配置文件。目前,我有一个庞大的“if-then”代码块,其中来自文件的切分字符串与结构体的不同元素相关联,类似这样:

if strings.Contains(tmpStr[0], "option1"){
     optionsStruct.Option1 = tmpStr[1]
}else if strings.Contains(tmpStr[0], "option2"){
    optionsStruct.OptionTwo = tmpStr[1]
} // 以此类推...

我想要更简洁的方式,更接近这样:

    for _, part := range splittedUpString{
         varnamestring = varNameString(part)
         optionsStruct.varnamestring = part
    } // 或者类似这样的代码

这样,我就不会重蹈“新平均系统”梗的覆辙。我不知道如果“optionsStruct”没有匹配的元素会是什么情况。

如果我在这里完全搞错了方向,请告诉我。很可能我从一开始就完全走错了路。


更多关于Golang中如何将变量名转换为字符串名的实战教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

我记得当时想用映射(map),但我不记得为什么最终没有采用它。

更多关于Golang中如何将变量名转换为字符串名的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


也许该再给 map 一次机会了…… 😄

我正在构建一个分布式视频监控系统。在树莓派上运行着“眼球”进程。这些进程会将数据以“帧”结构体的形式,通过gob编码后,传递给分类器、运动检测器和后端存储进程。这些进程可以运行在树莓派上,也可以运行在其他机器上。我有一个包,它读取一个公共配置文件,用于设置不同进程监听的端口、发送端口,并提供分类器XML文件的位置等信息。

除了@skillian的建议,如果配置文件是或者可以做成标准配置格式(如YAML、TOML、JSON等),您就可以使用现有的包来为您解析。(请在pkg.go.dev上搜索。)

此外,选项变量必须是结构体吗?如果您改用map[string]string,就可以毫不费力地存储从配置文件读取器传来的配置键和值。

func main() {
    fmt.Println("hello world")
}

根据你在这里展示的用例,我会这样做:Go Playground - The Go Programming Language

然而,这有点像“不稳定平衡”的解决方案:任何关于你在做什么,尤其是为什么要这么做的额外细节和上下文,几乎肯定会改变我的答案!

我选择这种显式的映射方式,是因为你将 "option2" 映射到了一个名为 OptionTwo 的字段。如果你的结构体字段名称直接映射到选项字符串,或者字段的标签包含了选项字符串名称,那么你可以使用 reflect 包来自动匹配所有内容,而无需显式地使用一个由设置函数组成的切片。我选择使用切片而不是映射,是因为如果你必须遍历每个元素来检查某个字符串是否包含键,那么使用映射就没有意义。如果你告诉我可能有成千上万甚至更多的键,那么我可能会对如何组织数据提出另一个建议。

看着你这里的代码,我在想当一个键包含 "option1option2" 时应该发生什么,但也许这种情况永远不会发生。就像我说的:有了任何额外的细节,我可能会建议一个完全不同的解决方案 耸肩表情 微笑表情

我之所以提出这些,完全是因为你说过:

如果我完全搞错了方向,请告诉我。

如果你想要的只是将子字符串映射到设置字段的代码,那么这似乎是一种合理的方式,但如果你“退一步”告诉我们你为什么这样做,那么我们可能会有一个更好的答案。例如,如果这个 tmpStr 是从 JSON 解析出来的,那么我敢打赌,这可以通过一些结构体标签和一个函数调用来解决!

在Go语言中,可以通过反射(reflect)来实现将结构体字段名与字符串进行匹配。以下是一个示例实现:

package main

import (
    "fmt"
    "reflect"
    "strings"
)

type Config struct {
    Option1    string `config:"option1"`
    OptionTwo  string `config:"option2"`
    ServerHost string `config:"server_host"`
    Port       int    `config:"port"`
}

func SetFieldByTag(config interface{}, key, value string) error {
    v := reflect.ValueOf(config).Elem()
    t := v.Type()

    for i := 0; i < v.NumField(); i++ {
        field := t.Field(i)
        tag := field.Tag.Get("config")
        
        if tag == key {
            fieldValue := v.Field(i)
            
            switch fieldValue.Kind() {
            case reflect.String:
                fieldValue.SetString(value)
            case reflect.Int:
                // 这里需要添加类型转换和错误处理
                // 简化示例,假设value是有效的int
                var intVal int
                fmt.Sscanf(value, "%d", &intVal)
                fieldValue.SetInt(int64(intVal))
            }
            return nil
        }
    }
    
    return fmt.Errorf("field with tag %s not found", key)
}

func main() {
    config := &Config{}
    
    // 模拟从配置文件读取的数据
    configLines := []string{
        "option1:value1",
        "option2:value2",
        "server_host:localhost",
        "port:8080",
    }
    
    for _, line := range configLines {
        parts := strings.Split(line, ":")
        if len(parts) == 2 {
            key := strings.TrimSpace(parts[0])
            value := strings.TrimSpace(parts[1])
            
            err := SetFieldByTag(config, key, value)
            if err != nil {
                fmt.Printf("Warning: %v\n", err)
            }
        }
    }
    
    fmt.Printf("Config: %+v\n", config)
}

另一种方法是使用map来存储配置,然后使用encoding/json或mapstructure库进行解码:

package main

import (
    "fmt"
    "github.com/mitchellh/mapstructure"
)

type Config struct {
    Option1   string `mapstructure:"option1"`
    OptionTwo string `mapstructure:"option2"`
}

func main() {
    configMap := map[string]interface{}{
        "option1": "value1",
        "option2": "value2",
    }
    
    var config Config
    err := mapstructure.Decode(configMap, &config)
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("Config: %+v\n", config)
}

如果不想使用第三方库,可以使用标准库的encoding/json:

package main

import (
    "encoding/json"
    "fmt"
)

type Config struct {
    Option1   string `json:"option1"`
    OptionTwo string `json:"option2"`
}

func main() {
    jsonStr := `{"option1": "value1", "option2": "value2"}`
    
    var config Config
    err := json.Unmarshal([]byte(jsonStr), &config)
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("Config: %+v\n", config)
}

对于配置文件解析,也可以考虑使用viper这样的配置管理库:

package main

import (
    "fmt"
    "github.com/spf13/viper"
)

type Config struct {
    Option1   string
    OptionTwo string
}

func main() {
    viper.SetConfigName("config")
    viper.SetConfigType("yaml")
    viper.AddConfigPath(".")
    
    err := viper.ReadInConfig()
    if err != nil {
        panic(fmt.Errorf("fatal error config file: %w", err))
    }
    
    var config Config
    err = viper.Unmarshal(&config)
    if err != nil {
        panic(err)
    }
    
    fmt.Printf("Config: %+v\n", config)
}

这些方法都可以避免使用大量的if-else语句,并提供更清晰、可维护的配置解析方案。

回到顶部