Go Wiki: 如何提问
简短介绍
想象一下,您想知道如何从“旧街”到“新街”。您打电话给一个陌生人寻求帮助,并问道:“我如何才能最快地从旧街 19 号到新街 3 号?”这位陌生人能帮到您吗?
世界上有很多“新”街和“旧”街,所以他首先需要知道您在哪个国家和城市。如果街道布局很复杂,那么您可能需要说出您附近的一些建筑物。当然,因为速度很重要,所以您的交通方式也很重要;您是步行、骑自行车、开车还是开车?您可以步行到达卡车无法到达的地方。
关于“我如何做 X?”这个直接问题的问题周围的上下文,有助于他人了解问题。在没有上下文的情况下给出建议可能意味着对方会描述错误的城市。
面对面提问很容易,而且可以连续快速地进行,尽管在论坛上这样做会导致大量的来回提问,而这些提问是可以避免的。那么,如何正确地为问题提供上下文呢?
如何提出一个好问题
论坛上的人们可用的时间有限。所以,为了加快速度,这里有一个提问的小模板,可以帮助您更快地获得更好的答案。
您遇到的问题的要点。
您是如何遇到这个问题的?
您试图完成什么?
问题的上下文是什么?
解决方案有哪些要求?
有哪些特定于上下文的约束/属性?
您的可编译和可运行的示例在 play.golang.org 上
关于情况的其他说明(生产/学校/玩耍/学习)
需要注意的事项
- 花点时间进行拼写检查,并确保您的句子可读。
- 解决方案可能与直接问题相距甚远。所以请确保问题包含 5 个为什么的答案。模板已经隐含了 3 个为什么的答案。
- 问题的上下文很重要,所以请务必提供。不提供上下文可能会对您不利,因为您会得到一个更适合不同上下文的答案。上下文是最终用户或领域问题和目标,以及它如何尝试解决该问题的信息。
- 尽量不要问抽象的问题,但如果确实要问,请提供多个具体的例子。不带具体例子的抽象问题(通常)会浪费时间。尽管它们有时可能很有趣,但具体的例子可以使讨论更精确。
- 避免使用“大量数据”或“需要快速运行”等不精确的术语。提供可衡量的东西,例如“它需要处理高达 1GB 的数据”或“它需要在 100 毫秒内与 1000 个并发客户端通信”。
- 如果您无法提供可编译的 Go 示例,使用任何语言都可以……很多人精通其他语言。如果您无法使其编译或运行,那也没关系。
- 试着解释您的情况
- 注明“这是家庭作业”意味着人们可以多做一些解释,而不会替您完成家庭作业。
- 诸如“它需要在 X 个节点群集上运行”之类的信息可以提供情境上下文。代码最终在哪里以及如何运行。
- 注明“这是为了学习 X”可以清楚地表明您正在努力深入了解不同的方法。
- 注明“我处于保密协议之下,无法披露代码”,意味着人们不会再费力询问。虽然您仍然应该尝试提出一个类似的情况,但它有助于回答者。
- 注明“这是家庭作业”意味着人们可以多做一些解释,而不会替您完成家庭作业。
- 提供一个简化的示例可能对读者有所帮助,但不要忘记也提供完整版本。简化版本与完整版本不同,因此解决方案也可能不同。
当然,不要太担心……您无法回答所有可能的问题。没必要就整件事写一篇 4 页的文章。如果需要澄清,人们可以随时提问。
一个糟糕问题的故事
为什么那个模板是必需的?让我们站在回答者的角度,假设您收到这样的问题:
如何使用 `reflect` 包的 `Set` 方法?
从提问者的角度来看,这可能看起来是一个简单的问题。当然,您不知道提问者想做什么。他是想在值、结构体、数组还是映射上设置值?这意味着您需要问第一个问题:*您能给个例子吗?*
现在提问者将提供一个示例:
我基本上想这样做:
但它总是会 panic。m := make(map[string]int)
v := reflect.ValueOf(m)
key := reflect.ValueOf("hello")
val := reflect.ValueOf(123)
v.MapIndex(k).Set(val)
print(m)
现在您得到了一些甚至无法编译的代码。这意味着您需要将其复制粘贴到某处并修复错误。将其放到 play.golang.org 上可以更容易地看到问题(例如 play.golang.org/p/fCxBlL9V4Y)。
修复很简单;只需使用 `SetMapIndex` 即可。当然,这可能不是全部。提问者现在又遇到了另一个问题:
太好了,我解决了反射问题,但速度不够快。
如何让它更快?
“更快”是什么意思?他想做什么?所以您需要询问更多关于问题的细节。于是您问:*您想完成什么?*
我正在尝试实现一个可以存储泛型类型的 set 包。
好吧,好的,但这仍然没有回答为什么它需要更快。他为什么还要使用 `reflect`,而可以使用 `map` 代替呢?所以您回答:*您不能只使用 `map` 代替(例如 `map[type]struct{}`)吗?您写这个 `set` 包是为了什么?*
我正在编写一个程序,它遍历多个序列并找到共同的元素。
主要用途是用于核苷酸,并且应该能够处理大型数据集。但它也应该能够处理蛋白质,它们由另一种类型表示。
是的,`map[NucleotideIndex]struct{}` 工作得更好一些,但仍然不够快,而且我现在必须为蛋白质编写相同的代码。
最后,我们获得了所有需要的信息。解决方案很简单:*`biogo` https://code.google.com/p/biogo/ 包含处理大型数据集和并行等所需的大部分内容。另外,“`NucleotideIndex`”是什么?*提问者可能已经找到了答案并说:*谢谢,这真的很好。*但也有可能
哇,这看起来不错,但我正在参加一个生物信息学课程,我们需要自己编写这段代码。“`NucleotideIndex`”是“`struct {Nucleotide Nucleotide; Index int}”。
这看起来很奇怪,为什么你要这样做。尽管如此,我们都做过愚蠢的事情,所以……现在您可以开始提出更好的建议了:*处理 `map[Type]map[int]struct{}` 可能会容易得多。因为您正在处理序列,并且集合元素总是按递增顺序使用的,所以您可以将索引存储在数组中,例如 `map[Type][]int`。另外,如果内存开始成为问题,您可以将其转换为行程长度编码的集合……*
现在我们可以就不同集合类型的(非)优点进行更有意义的讨论了。
希望经过这个漫长的例子,您大概明白了提供更多信息的好处。最初的来回提问本可以避免。一个好的问题本可以为提问者和回答者节省时间。
最初的问题本可以这样提:
如何使用 `reflect` 包的 `Set` 方法配合 `MapIndex`?
我试图为 set 包中的一个通用映射设置一个值。但当我尝试这样做时,它总是会 panic。 play.golang.org/p/fCxBlL9V4Y
我在一个遍历多个序列并查找序列中所有共同元素的程序中使用 set 包。序列元素可以是核苷酸或蛋白质。该程序需要能够处理高达 1GB 的数据大小。
我目前的 kode 可在 github.com/... 找到
我写这个是为了一个生物信息学课程,所以需要自己实现。
总结
- 最佳答案取决于上下文。在某些情况下,也许 research.swtch.com/sparse 会更合适。如果速度不重要,使用 `map` 就足够了。所以要求也很重要。
- 问题可能出在其他地方。正如您所见,回答者没有预料到程序结构是问题的根源。使用带有 `map` 的结构体 `NucleotideIndex`,意味着他不得不通过反射构建复杂的东西。通常,当您解决更高级别的问题时,其他所有事情都会变得容易得多。
- 约束/属性很重要。“集合元素按递增顺序使用”这一属性意味着有一个简单的方法,不需要完整的 `set` 实现。这种专门的结构可以快得多。关于系统、上下文或领域的信息可能会使问题简单得多。
- 解决方案可能与您通常的方法不同。也许提问者因为习惯了 Java 中的泛型而决定使用 `reflect` 包。Go 是一种不同的语言,所以最终的解决方案可能与 Java 中的解决方案大不相同。
更多技巧
此内容是 Go Wiki 的一部分。