🎯 什麼情境該想到我

當你「一個函式的本體跟它的名字一樣直白、沒帶來額外價值」,或是一群函式被切得太碎、間接層多到反而難懂的時候——把呼叫處直接換成函式本體,讓邏輯回到一起再重新整理。

⚙️ 怎麼用(步驟 / 公式)

意圖:當函式本體和名字一樣清楚時,去掉這層間接,把呼叫處換成本體。

動作要點(小步安全進行):

  1. 確認這不是多型方法(子類別有覆寫的就不能行內)。
  2. 找出所有呼叫這個函式的地方。
  3. 把每個呼叫逐一換成函式本體,每換一處就編譯、測試。
  4. 全部替換完成後,刪除原函式定義。
  5. 若替換過程變複雜(例如本體用到呼叫端沒有的東西),一次處理一個呼叫點,別急。

★ before / after(Go)

before——函式名沒比本體更清楚,只是多一層:

func rating(d *Driver) int {
    if moreThanFiveLateDeliveries(d) { return 2 }
    return 1
}
func moreThanFiveLateDeliveries(d *Driver) bool { return d.LateDeliveries > 5 }

after——本體本身就是最清楚的說法:

func rating(d *Driver) int {
    if d.LateDeliveries > 5 { return 2 }
    return 1
}

什麼時候該 inline(三個真實訊號)

訊號說明
名字沒比本體清楚isEmpty(s) 的本體是 len(s) == 0 —— 名字沒帶來理解價值
★ 一群組織不良的小函式先全部 inline 回一大坨,再重新提煉出對的切點。這是 Fowler 明說的用法
中間人:只轉發不做事func (s *S) Name() string { return s.inner.Name() } 一路轉發 5 層

★ Go 的陷阱:具名回傳值 + defer

func load(p string) (b []byte, err error) {
    defer func() {
        if err != nil { err = fmt.Errorf("load %s: %w", p, err) }   // ★ defer 改了回傳值
    }()
    return os.ReadFile(p)
}

把這種函式 inline 掉,會靜默丟掉錯誤包裝。 呼叫端的 errors.Is 還會通,
但錯誤訊息裡少了 load <path>: 這段脈絡——是行為改變,編譯器不會抗議。

另外兩個必查項:

  1. 匯出函式不能隨手 inline —— 別的 module 可能在呼叫。先確認呼叫者範圍(grep -rn,或 IDE 的 Find References)。
  2. 介面方法不能 inline —— 實際跑哪一份是執行期決定的。

⚠️ 不要和「編譯器 inline」搞混

這裡的 inline 是原始碼層的重構;Go 編譯器另外有自己的內聯優化,兩者無關。
實測 Go 1.26.4(2026-09-25):

./main.go:5:6:  can inline small with cost 4
./main.go:7:6:  can inline big with cost 73      ★ 含 for 迴圈的函式現在也能被內聯
./main.go:24:6: cannot inline main: function too complex: cost 163 exceeds budget 80

→ 你手動 inline 一個函式,不會讓程式變快;編譯器早就決定好了。

工具支援

gopls 有 refactor.inline.call,而且官方把 Inline 和 Rename 並列為「嚴謹」的操作(對比 Extract 被明說不嚴謹)。
但同樣有掉註解的問題(go.dev/issue/20744)。

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 若函式名字確實解釋了意圖、或會被多型覆寫、或呼叫點很多且分散,就不要行內。

  • 常見用途是先把一堆爛的小函式行內回一大段,再重新用提煉函式 Extract Function切出更合理的邊界。

  • 反向手法:提煉函式 Extract Function。

  • ★ 具名回傳值 + defer 改回傳值的函式,inline 掉會靜默改變行為(見上)。

  • 遞迴函式、被多處呼叫的函式、匯出的 API —— 不要 inline。

  • inline 會讓呼叫端變長。目的是「換掉一個壞的切點」,不是「減少函式數量」。若 inline 完沒有接著重新提煉,通常是白做。

  • 一次只 inline 一處,跑一次測試。批次 inline 十處然後測試紅了,你不知道是哪一處。

🔗 相關工具