英文:
golang: How to define a sequence of steps
问题
我想编写一个协议测试。我的当前想法是定义一系列步骤。每个步骤包含一个Trigger
和一个Expectation
,例如触发MsgA
并期望MsgB
。
type Series struct {
Steps []Step
}
我不喜欢这种方式的原因是,Series
不够明确:我要么按顺序创建切片,然后希望它永远不会出错并依赖它,要么对其进行sort
排序,然后必须实现排序函数,这是完全不必要的。
有什么好的设计方法可以正式定义Series
,并以这种方式使其明确?
我目前最好的想法是创建一个带有int
索引的映射:
type Series struct {
Steps map[int]Step
}
series := Series{
Steps: map[int]Step{
0: Step{},
1: Step{},
2: Step{},
...
}
}
另一个选择可能是构建一个链表。go
没有现成的实现(据我所知)。对于这个问题,我觉得自己构建一个链表有点奇怪。但这样的解决方案也会稍微失去明确性的特点:基本上,你总是需要通过链表导航来获取整个序列(例如,“第4步是什么”)。
英文:
I want to write a protocol test. My current idea is to define a series of steps. Each Step contains a Trigger
and Expectation
- e.g. trigger MsgA
and expect MsgB
.
type Series struct {
Steps []Step
}
What I don't like about this, is that the Series
is not explicit: I would have to either create the slice in sequence and then hope it never gets messed up, and rely on it, or sort
it and then have to implement the sort funcs, which is utterly unnecessary.
What is a good design to formally define the Series
, and in this way make it explicit?
The best idea I have for now is to create a map with int
indexes:
type Series struct {
Steps map[int]Step
}
series := Series{
Steps: map[int]Step{
0: Step{},
1: Step{},
2: Step{},
...
}
}
Another option could be to build myself a linked list. go
doesn't have an implementation (afaik). It feels odd to have to build one myself for this. But such a solution would also loose the explicit feature a bit: Basically you always have to navigate through the linked list to get the whole sequence (e.g. "what is step 4").
答案1
得分: 3
使用切片和键入的复合字面量,而不是使用映射:
var steps = []Step{
0: Step{},
1: Step{},
...
}
这在规范:复合字面量中有详细说明:
CompositeLit = LiteralType LiteralValue . LiteralType = StructType | ArrayType | "[" "..." "]" ElementType | SliceType | MapType | TypeName [ TypeArgs ] . LiteralValue = "{" [ ElementList [ "," ] ] "}" . ElementList = KeyedElement { "," KeyedElement } . KeyedElement = [ Key ":" ] Element . Key = FieldName | Expression | LiteralValue . FieldName = identifier . Element = Expression | LiteralValue .
如您所见,KeyedElement
可以包含可选的 Key ":"
部分。
... 对于结构体字面量,键被解释为字段名,对于数组和切片字面量,键被解释为索引,对于映射字面量,键被解释为键。
请注意,您可以混合使用键入和“非键入”元素,并且它们不必是连续的。此外,如果切片字面量中缺少键,则索引将是前一个索引加1。
type Step struct{}
var steps = []*Step{
0: &Step{},
1: &Step{},
&Step{}, // 隐式索引:2
5: &Step{},
}
fmt.Println(steps)
以上代码的输出结果(在Go Playground上尝试)为:
[0x559008 0x559008 0x559008 <nil> <nil> 0x559008]
键也可以是“无序”的,这也是有效的:
var steps = []*Step{
5: &Step{},
0: &Step{},
1: &Step{},
&Step{}, // 隐式索引:2
}
这将输出相同的结果。在Go Playground上尝试一下。
英文:
Instead of using a map, you can still use a slice and use a keyed composite literal:
var steps = []Step{
0: Step{},
1: Step{},
...
}
This is detailed in Spec: Composite literals:
> CompositeLit = LiteralType LiteralValue .
> LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
> SliceType | MapType | TypeName [ TypeArgs ] .
> LiteralValue = "{" [ ElementList [ "," ] ] "}" .
> ElementList = KeyedElement { "," KeyedElement } .
> KeyedElement = [ Key ":" ] Element .
> Key = FieldName | Expression | LiteralValue .
> FieldName = identifier .
> Element = Expression | LiteralValue .
As you can see, KeyedElement
may contain an optional Key ":"
part.
> ... The key is interpreted as a field name for struct literals, an index for array and slice literals, and a key for map literals.
Note that you can mix keyed and "unkeyed" elements, and they don't have to be contiguous. Also, if a key is missing in a slice literal, the index will be the previous index + 1.
type Step struct{}
var steps = []*Step{
0: &Step{},
1: &Step{},
&Step{}, // implicit index: 2
5: &Step{},
}
fmt.Println(steps)
Output of the above (try it on the Go Playground):
[0x559008 0x559008 0x559008 <nil> <nil> 0x559008]
They keys may also be "out of order", meaning this is also valid:
var steps = []*Step{
5: &Step{},
0: &Step{},
1: &Step{},
&Step{}, // implicit index: 2
}
This outputs the same. Try it on the Go Playground.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论