Go map 的通用值类型

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

Generic value type of Go map

问题

我正在使用Go语言开发一个Web应用程序。respond(writer, html, *params)函数需要一个参数列表,用于渲染HTML页面。我使用了一个map来实现这个功能,目前运行良好:

map[string][]string

然而,最近我需要插入一个格式为{string, map[string][]string}的键值对,这显然导致了编译错误。所以我想知道是否有任何通用类型可以使用,比如map[string]GenericType

欢迎提出任何想法。

英文:

I am working on a web app with Go language. The respond(writer, html, *params) function needs a list of parameters which can be used to render an HTML page. I came up with a map as this which works fine:

&map[string][]string

However, recently I need to squeeze in a value pair in the format of {string, map[string][]string} which obviously blew up the compiler. So I am wondering if there is any generic type I can utilize, i.e. map[string]GenericType.

Any thoughts is welcomed.

答案1

得分: 4

通常情况下,你会为string键存储[]string值。大部分情况下都是这样。偶尔你可能想要为string键存储一个map[string][]string值。

首先,从映射类型中去掉指针:映射已经是小型描述符了,你可以传递映射,这将传递描述符的副本而不是整个内容,如果你向副本中添加一个新的键值对,你将在原始映射中看到这个变化。通过值传递映射是高效的,并且具有期望的效果/工作方式。

要精确一点:映射类型实际上是指向底层映射描述符的指针,但这是一个实现细节,你不需要知道这个来使用/处理映射。唯一重要的是你可以有效地传递映射值。

如果你想保留一个映射并且能够存储[]stringmap[string][]string两种类型的值,你需要将值类型更改为interface{},但这将要求你在访问params映射中的每个元素时都使用类型断言,类似于:

params := map[string]interface{}{}
params["a"] = []string{"b", "c"}

if list, ok := params["a"].([]string); ok {
    fmt.Println(list)
}

当然,你可以创建一个新类型,其底层类型为map[string]interface{},并为最常见的值类型[]string添加Get()Set()方法,但我建议你使用一个包装的struct来作为params的容器,其中包含多个字段的映射:

type Params struct {
    P map[string][]string
    M map[string]map[string][]string
}

你的代码可以使用适合存储值的值类型的映射,例如:

params2 := Params{map[string][]string{}, map[string]map[string][]string{}}
params2.P["a"] = []string{"b", "c"}

params2.M["B"] = map[string][]string{
    "x": []string{"X", "Y"},
}

fmt.Println(params2.P["a"])
fmt.Println(params2.M["B"])

你还可以为Params添加Get()Set()方法,用于从最常用的Params.P映射中获取和设置元素。

Go Playground上尝试一下。

英文:

So generally you store []string values for string keys. Most of the time. And once in a while you'd like to store a map[string][]string value for a string key.

First, drop the pointer from the map type: maps are already small descriptors, you can pass maps which will pass a copy of the descriptor and not the whole content, and if you add a new key-value pair to the copy, you will see that in the original. Passing a map by value is efficient and has the desired effect / working.

<sup>To be precise: map types are actually pointers to a map descriptor under the hood, but this is an implementation detail, you don't need to know this to use / work with maps. Only thing that matters is you can pass around map values efficiently.</sup>

Keeping only one map and being able to store values of both type []string and map[string][]string would require you to change the value type to interface{}, but then this would require you to use Type assertion every time you access an element in the params map, something like:

params := map[string]interface{}{}
params[&quot;a&quot;] = []string{&quot;b&quot;, &quot;c&quot;}

if list, ok := params[&quot;a&quot;].([]string); ok {
	fmt.Println(list)
}

Of course you could create a new type with map[string]interface{} being its underlying type, and add Get() and Set() methods for the most common value type []string, but instead I recommend a wrapper struct for the params, with multiple maps in multiple fields:

type Params struct {
	P map[string][]string
	M map[string]map[string][]string
}

Your code may use the map whichever has the value type that suits the value to be stored, for example:

params2 := Params{map[string][]string{}, map[string]map[string][]string{}}
params2.P[&quot;a&quot;] = []string{&quot;b&quot;, &quot;c&quot;}

params2.M[&quot;B&quot;] = map[string][]string{
	&quot;x&quot;: []string{&quot;X&quot;, &quot;Y&quot;},
}

fmt.Println(params2.P[&quot;a&quot;])
fmt.Println(params2.M[&quot;B&quot;])

You may also add Get() and Set() methods to Params that get and set elements from the most frequently used Params.P map.

Try it on the Go Playground.

huangapple
  • 本文由 发表于 2015年11月20日 09:37:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/33817562.html
匿名

发表评论

匿名网友

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

确定