這篇文章是關于一個鮮為人知的讓 go 在編譯期斷言的方法。你可能不會使用它,但是了解一下也很有趣。
作為一個熱身,來看一個在 go 中熟知的編譯期斷言:接口滿意度檢查。
<code>package main</code>
<code></code>
<code>import "io"</code>
<code>type w struct{}</code>
<code>func (w w) write(b []byte) (int, error) { return len(b), nil }</code>
<code>func (w w) writestring(s string) (int, error) { return len(s), nil }</code>
<code>type stringwriter interface {</code>
<code>writestring(string) (int, error)</code>
<code>}</code>
<code>var _ stringwriter = w{}</code>
<code>func main() {</code>
<code>var w w</code>
<code>io.writestring(w, "very long string")</code>
如果你注釋掉了 <code>w</code> 的 <code>writestring</code> 方法,代碼将無法編譯:
<code>main.go:14: cannot use w literal (type w) as type stringwriter in assignment:</code>
<code>w does not implement stringwriter (missing writestring method)</code>
這是很有用的。對于大多數同時滿足 <code>io.writer</code> 和 <code>stringwriter</code> 的類型,如果你删除 <code>writestring</code> 方法,一切都會像以前一樣繼續工作,但性能較差。
好的,讓我們低調一點!
接口滿意檢查是很棒的。但是如果你想檢查一個簡單的布爾表達式,如 <code>1 + 1 == 2</code> ?
<code>import "crypto/md5"</code>
<code>type hash [16]byte</code>
<code>func init() {</code>
<code>if len(hash{}) < md5.size {</code>
<code>panic("hash is too small")</code>
<code>// ...</code>
如下。(沒有 playground 連結,因為這在 playground 上不起作用。)
<code>import "c"</code>
<code>func hashistoosmall()</code>
<code>hashistoosmall()</code>
現在如果你改變 <code>hash</code> 為 <code>[8]byte</code>,它将在編譯過程中失敗。(實際上,它在連結過程中失敗。足夠接近我們的目标了。)
<code>$ go build .</code>
<code># demo</code>
<code>main.hashistoosmall: call to external function</code>
<code>main.init.1: relocation target main.hashistoosmall not defined</code>
<code>main.init.1: undefined: "main.hashistoosmall"</code>
這裡發生了什麼?
當編譯器可以證明 <code>len(hash {})< md5.size</code> 時,它消除了 if 語句中的代碼。結果,沒有人使用函數<code>hashistoosmall</code>,是以連結器會消除它。沒有其他損害。一旦斷言失敗,if 語句中的代碼将被保留。不會消除<code>hashistoosmall</code>。連結器然後注意到沒有人提供了函數的實作然後連結失敗,并出現錯誤,這是我們的目标。
原文釋出時間為:2017-03-28
本文來自雲栖社群合作夥伴“linux中國”