如何为结构体提供字符串格式化?

5

我有一个名为item的结构体

type Item struct {
    Limit int
    Skip int
    Fields string
}



item := Item {
            Limit: 3,
            Skip: 5,
            Fields: "Valuie",
    }

我该如何获取字段名和值并将它们连接成一个字符串。

类似这样:

item := Item {
            Limit: 3,
            Skip: 5,
            Fields: "Valuie",
    }

将某物转换为类似字符串的形式
"Limit=3&Skip=5&Fields=Valuie"

我已经尝试使用反射将接口转换为字段值映射,这样做正确吗?因为我认为可能有更好的解决方案。谢谢!

m, _ = reflections.Items(data)
for k, v := range m {
    fmt.Printf("%s : %s\n", k, v)
}

我已经得到了

Limit : %!s(int=3)
Skip : %!s(int=5)
Fields : Valuie
4个回答

10
您可以使用 %v 替代 %s。%s 会假定一个字符串,即可转换为字符串的内容(例如字节数组)或具有 String() 方法的对象。 使用 %v 将检查类型并正确地显示其内容。
在您的示例中,使用 %s 调用了 String() 方法,示例如下:http://play.golang.org/p/bxE91IaVKj

抱歉,请问 v = &url.Values{} 是用来做什么的? - LiJung
1
看起来你试图伪造URL值。url.Values是一个带有几个方法的映射,可帮助您完成此操作。您可以将其删除并使用Sprintf自行伪造它。 - creack
有进一步的问题,我如何将创建的字符串连接并返回到URL中?类似于http://localhost:3000/?limit=3&skip=5。是否有简单的解决方案? - LiJung
不确定是否理解。类似这样的:http://play.golang.org/p/SjBMmR2InT? - creack
@creack,您没有提供完整的答案。请考虑在您的回答中包含相关代码,不要依赖外部网站。 - nemo

3

这并不需要使用反射。只需编写您拥有的类型的代码即可。

func (i *Item) URLValues() string {
    uv := url.Values()
    uv.Set("Limit", strconv.Itoa(i.Limit))
    uv.Set("Skip", strconv.Itoa(i.Skip))
    uv.Set("Fields", i.Fields)
    return uv.Encode()
}

这段代码简单易读,不需要费太多脑力就能编写。除非您需要转换很多类型到值之间的映射,否则我甚至不会考虑使用基于魔法反射的解决方案。


1
对于任何结构体,您可以使用反射和来自net/url包的url.Values
i := Item{1, 2, "foo"}

v := url.Values{}
ri := reflect.ValueOf(i)

ri.FieldByNameFunc(func(name string) bool {
    v.Set(name, fmt.Sprintf("%v", ri.FieldByName(name).Interface()))
    return false
})

fmt.Println(v.Encode())

播放示例

当然,这段代码不能处理嵌套的数据结构或切片,因此如果您使用其他数据结构使其更加通用,就需要扩展该代码。但是,这个示例应该能让您入门。


有趣,但似乎不起作用。字符串字段没有被 FieldByNameFunc 调用。 - creack
抱歉,已修复示例。当返回true时,FieldByNameFunc会中止搜索,因此在此处应返回false - nemo

0

看一下go-querystring。它可以将一个结构体转换为URL查询参数(你期望的输出)。

type Item struct {
  Limit  int    `limit:"limit"`
  Skip   int    `url:"skip"`
  Fields string `url:"fields"`
}

item := Item {
  Limit: 3,
  Skip: 5,
  Fields: "Valuie",
}

v, _ := query.Values(item)
fmt.Print(v.Encode()) 
// will output: "limit=3&skip=5&fields=Valuie"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接