Golang 技巧:type switch / pp

首先是 type switch,主因是很多 API 或 lib 都會接到 interface,但要轉回原形時可以使用類似

imInt := wtf.(int)

但來源可能會有很多種,所以有幾招可以用,類似

source := 123
fmt.Sprintf("%T" , source) //=> "int"

單純拿 fmt 來轉,或是這邊要說的 type switch,資料來源

switch v := sourceInterface.(type) {
case int:
    fmt.Printf("Integer: %v", v)
case string:
    fmt.Printf("String: %v", v)
default:
    fmt.Printf("I don't know, %T(%+v)" , v , v)
}

基本上後面的 v 已經被轉回 case 後面的資料型態,所以後面就直接處理即可,而如果為 struct 的話,跑到 default 那段時,%T 可以顯示原本定義,而 %+v 可以顯示連同 field name + value 一起顯示,而非單純的 fmt 系列只有顯示 value 而已還要猜半天(詳細內容可以對照 fmt 的 doc

至於額外的 … golang 的一票鬼東西"很難看",我指的是 Ruby 內的 awesome_print 和 pp 都超好用的,但 golang 預設的資料顯示很糟,直到我找到這個 lib

嗯 … 很好非常的符合需求哈哈哈 … 不過因為所有的 string 都會被加上 “xxx” 且紅色的很難看,所以我自己做個 relay 就是,類似 logger 中間使用類似的封裝過

func loggerMergeMsg(argvs ...interface{}) string {
	var ans string
	isFirst := true
	for _, value := range argvs {
		if isFirst {
			ans = loggerField(value)
			isFirst = false
		} else {
			ans = fmt.Sprintf("%s | %s", ans, loggerField(value))
		}
	}
	return ans
}

func loggerField(sourceValue interface{}) string {
	// 排除該單純項次為 string 時不上 pp ... 不然好亂啊
	switch targetValue := sourceValue.(type) {
	case string:
		return targetValue
	case *string:
		return fmt.Sprintf(`*"%s"`, *targetValue)
	default:
		return pp.Sprint(targetValue)
	}
}

即為所求,很漂亮也很好用就是(當然我實作的 logger 還有加上額外的狀態碼封裝就是)