這篇文章是關於乙個鮮為人知的讓 go 在編譯期斷言的方法。你可能不會使用它,但是了解一下也很有趣。
作為乙個熱身,來看乙個在 go 中熟知的編譯期斷言:介面滿意度檢查。
在這段**(playground)中,var _ =
行確保型別w
是乙個stringwriter
,其由io.writestring
檢查。
package
main
import
"io"
type w
struct
{}
func (w
w)write(b
byte)(
int,
error
)
func (w
w)writestring
(s string)(
int,
error
)
type stringwriter
inte***ce
var
_ stringwriter =w
{}
func main
()
如果你注釋掉了w
的writestring
方法,**將無法編譯:
main.go
:14:cannot
usew literal
(type w)as
type stringwriter
inassignment
:
w does
notimplement stringwriter
(missing
writestring
method
)
這是很有用的。對於大多數同時滿足io.writer
和stringwriter
的型別,如果你刪除writestring
方法,一切都會像以前一樣繼續工作,但效能較差。
你可以使用編譯期斷言保護你的**,而不是試圖使用`testing.t.allocsperrun'為效能回歸編寫乙個脆弱的測試。
這是乙個實際的 io 包中的技術例子。
好的,讓我們低調一點!
介面滿意檢查是很棒的。但是如果你想檢查乙個簡單的布林表示式,如1 + 1 == 2
?
考慮這個**(playground):
package
main
import
"crypto/md5"
type
hash[16
]byte
func
init())
<
md5.
size
}
func main
()
hash
可能是某種抽象的雜湊結果。init
函式確保它將與 crypto/md5 一起工作。如果你改變hash
為(比如說)[8]byte
,它會在程序啟動時發生崩潰。但是,這是乙個執行時檢查。如果我們想要早點發現怎麼辦?
如下。(沒有 playground 鏈結,因為這在 playground 上不起作用。)
package
main
import
"c"
import
"crypto/md5"
type
hash[16
]byte
func hashistoosmall
()
func
init())
<
md5.
size
}
func main
()
現在如果你改變hash
為[8]byte
,它將在編譯過程中失敗。(實際上,它在鏈結過程中失敗。足夠接近我們的目標了。)
$ go build
.
#
demo
main
.hashistoosmall
:call to external
function
main
.init.1
:relocation target main
.hashistoosmall
notdefined
main
.init.1
:undefined
:"main.hashistoosmall"
這裡發生了什麼?
hashistoosmall
是乙個沒有函式體的宣告。編譯器假定別人將提供乙個實現,也許是乙個匯程式設計序。
當編譯器可以證明len(hash {})< md5.size
時,它消除了 if 語句中的**。結果,沒有人使用函式hashistoosmall
,所以鏈結器會消除它。沒有其他損害。一旦斷言失敗,if 語句中的**將被保留。不會消除hashistoosmall
。鏈結器然後注意到沒有人提供了函式的實現然後鏈結失敗,並出現錯誤,這是我們的目標。
最後乙個奇怪的點:為什麼是import "c"
? go 工具知道在正常的 go **中,所有函式都必須有主體,並指示編譯器強制執行。通過切換到 cgo,我們刪除該檢查。(如果你在上面的**中執行go build -x
,而沒有新增import "c"
這行,你會看到編譯器是用-complete
標誌呼叫的。)另一種方法是新增import "c"
來向包中新增乙個名為foo.s
的空檔案。
我僅見過一次這種技術的使用,是在編譯器測試套件中。還有其他可以發揮想象力的使用,但我還沒見到過。
原文發布時間為:2017-03-28
執行期斷言和編譯期斷言
編譯時斷言和執行時斷言 通常為了檢測一些條件,我們往往在程式裡面加斷言。一般只在debug版有效,release版斷言不生成任何 c 可以使用兩種斷言 靜態斷言和動態斷言,即就是執行期斷言和編譯期斷言!顧名思義,執行期斷言是在程式執行過程中判斷指定的條件,若條件滿足,萬事ok,若斷言失敗,則程式給出...
go語言的型別斷言 Type Assertion
x.t 檢查x的動態型別是否是t,其中x必須是介面值。如果t是具體型別 型別斷言檢查x的動態型別是否等於具體型別t。如果檢查成功,型別斷言返回的結果是x的動態值,其型別是t。換句話說,對介面值x斷言其動態型別是具體型別t,若成功則提取出x的具體值。如果檢查失敗則panic。例如 var w io.w...
Go型別斷言
package main import fmt 型別斷言 type assertion 是乙個使用在介面值上的操作,用於檢查介面型別變數所持有的值是否實現了期望的介面或者具體的型別。如何進行型別斷言的判斷?1.使用if語句或者switch語句 2.依靠 value,ok x.t x 表示乙個介面的型...