Go Wiki: 如何提問

簡短介紹

想象一下,您想知道如何從“舊街”到“新街”。您打電話給一個陌生人尋求幫助,並問道:“我如何才能最快地從舊街 19 號到新街 3 號?”這位陌生人能幫到您嗎?

世界上有很多“新”街和“舊”街,所以他首先需要知道您在哪個國家和城市。如果街道佈局很複雜,那麼您可能需要說出您附近的一些建築物。當然,因為速度很重要,所以您的交通方式也很重要;您是步行、騎腳踏車、開車還是開車?您可以步行到達卡車無法到達的地方。

關於“我如何做 X?”這個直接問題的問題周圍的上下文,有助於他人瞭解問題。在沒有上下文的情況下給出建議可能意味著對方會描述錯誤的城市。

面對面提問很容易,而且可以連續快速地進行,儘管在論壇上這樣做會導致大量的來回提問,而這些提問是可以避免的。那麼,如何正確地為問題提供上下文呢?

如何提出一個好問題

論壇上的人們可用的時間有限。所以,為了加快速度,這裡有一個提問的小模板,可以幫助您更快地獲得更好的答案。

您遇到的問題的要點。


您是如何遇到這個問題的?
您試圖完成什麼?
問題的上下文是什麼?
解決方案有哪些要求?
有哪些特定於上下文的約束/屬性?
您的可編譯和可執行的示例在 play.golang.org

關於情況的其他說明(生產/學校/玩耍/學習)

需要注意的事項

  • 花點時間進行拼寫檢查,並確保您的句子可讀。
  • 解決方案可能與直接問題相距甚遠。所以請確保問題包含 5 個為什麼的答案。模板已經隱含了 3 個為什麼的答案。
  • 問題的上下文很重要,所以請務必提供。不提供上下文可能會對您不利,因為您會得到一個更適合不同上下文的答案。上下文是終端使用者或領域問題和目標,以及它如何嘗試解決該問題的資訊。
  • 儘量不要問抽象的問題,但如果確實要問,請提供多個具體的例子。不帶具體例子的抽象問題(通常)會浪費時間。儘管它們有時可能很有趣,但具體的例子可以使討論更精確。
  • 避免使用“大量資料”或“需要快速執行”等不精確的術語。提供可衡量的東西,例如“它需要處理高達 1GB 的資料”或“它需要在 100 毫秒內與 1000 個併發客戶端通訊”。
  • 如果您無法提供可編譯的 Go 示例,使用任何語言都可以……很多人精通其他語言。如果您無法使其編譯或執行,那也沒關係。
  • 試著解釋您的情況
    • 註明“這是家庭作業”意味著人們可以多做一些解釋,而不會替您完成家庭作業。
    • 諸如“它需要在 X 個節點群集上執行”之類的資訊可以提供情境上下文。程式碼最終在哪裡以及如何執行。
    • 註明“這是為了學習 X”可以清楚地表明您正在努力深入瞭解不同的方法。
    • 註明“我處於保密協議之下,無法披露程式碼”,意味著人們不會再費力詢問。雖然您仍然應該嘗試提出一個類似的情況,但它有助於回答者。
  • 提供一個簡化的示例可能對讀者有所幫助,但不要忘記也提供完整版本。簡化版本與完整版本不同,因此解決方案也可能不同。

當然,不要太擔心……您無法回答所有可能的問題。沒必要就整件事寫一篇 4 頁的文章。如果需要澄清,人們可以隨時提問。

一個糟糕問題的故事

為什麼那個模板是必需的?讓我們站在回答者的角度,假設您收到這樣的問題:

如何使用 `reflect` 包的 `Set` 方法?

從提問者的角度來看,這可能看起來是一個簡單的問題。當然,您不知道提問者想做什麼。他是想在值、結構體、陣列還是對映上設定值?這意味著您需要問第一個問題:*您能給個例子嗎?*

現在提問者將提供一個示例:

我基本上想這樣做:
    m := make(map[string]int)
v := reflect.ValueOf(m)
key := reflect.ValueOf("hello")
val := reflect.ValueOf(123)
v.MapIndex(k).Set(val)
print(m)
但它總是會 panic。

現在您得到了一些甚至無法編譯的程式碼。這意味著您需要將其複製貼上到某處並修復錯誤。將其放到 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 的一部分。