英文:
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
值。
首先,从映射类型中去掉指针:映射已经是小型描述符了,你可以传递映射,这将传递描述符的副本而不是整个内容,如果你向副本中添加一个新的键值对,你将在原始映射中看到这个变化。通过值传递映射是高效的,并且具有期望的效果/工作方式。
要精确一点:映射类型实际上是指向底层映射描述符的指针,但这是一个实现细节,你不需要知道这个来使用/处理映射。唯一重要的是你可以有效地传递映射值。
如果你想保留一个映射并且能够存储[]string
和map[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["a"] = []string{"b", "c"}
if list, ok := params["a"].([]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["a"] = []string{"b", "c"}
params2.M["B"] = map[string][]string{
"x": []string{"X", "Y"},
}
fmt.Println(params2.P["a"])
fmt.Println(params2.M["B"])
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论