這是我純手寫的《go語言入門》,手把手教你入門go。原始碼+文章,看了你就會?,此處應有掌聲???!文章中所有的**我都放到了github.com/ganzhixiong/go_learning這個倉庫中。在看文章的時候,對照倉庫中**學習效果更佳!
nil介面變數無論斷言什麼型別都會失敗
判斷介面值是否有某乙個或多個方法?
如何判斷乙個非介面值的變數是否是某個型別呢?
總結支援?
型別斷言(type assertion)是乙個使用在介面值上的操作,用於檢查介面型別變數所持有的值是否實現了期望的介面或者具體的型別。
有些時候你可能會寫出下面這樣的**:
func
funcname
(a inte***ce
)string
' to type 'string'
return
string
(a)}
但是這樣寫是編譯不通過的,「無法將型別「inte***ce{}」的表示式轉換為型別「string」」這個報錯很明顯,這時候型別轉換就需要用到型別斷言了。
其語法如下:
value, ok := x.
(t)
需要記住的是:
func
testtypeassertion
(t *testing.t)
x =10 t.
log(x, reflect.
typeof
(x))
value, ok := x.
(int
) t.
log(value, ok)
t.log()
x =1.2 t.
log(x, reflect.
typeof
(x))
value, ok = x.
(int
)// 斷言失敗後,value為t型別,value為t型別的預設值
t.log
(value, reflect.
typeof
(value)
, ok)
// 0 false
// cannot assign float32 to value (type int) in multiple assignment
//value, ok := x.(float32)
value1, ok := x.
(float32
) t.
log(value1, ok)
value2, ok := x.
(float64
) t.
log(value2, ok)
}
該語法省略了ok。
value := x.
(t)
但是不推薦使用,因為一旦斷言失敗,就會產生panic。
func
testtypeassertionpanic
(t *testing.t)
x ="hello"
value, ok := x.
(string
) t.
log(value, ok)
value1 := x.
(string
) t.
log(value1)
value2, ok := x.
(int
) t.
log(value2, ok)
// 如果斷言失敗,省略了ok則會panic。
value3 := x.
(int
) t.
log(value3)
}
如果需要區分多種型別,可以使用 type switch 斷言,這個將會比乙個乙個進行型別斷言更簡單、直接、高效。
語法:
switch value := element.
(type
)
或
switch element.
(type
)
需要注意的是element.(type)只能搭配switch使用。
func
gettype
(a inte***ce)}
func
testtypeassertionswitch
(t *testing.t)
type html [
]inte***ce
func
testtypeassertionswitch1
(t *testing.t)
}}
// 如果斷言的是nil介面變數,那麼無論被斷言的型別是什麼這個型別斷言都會失敗
func
testtani
(t *testing.t)
value1, ok := i.
(inte***ce
) t.
log(value1, ok)
}// 如果斷言的是具體值為nil的介面變數,則不會失敗
func
testtanil1
(t *testing.t)
直接看下面的**吧:
/*
為了解決writeheader函式中write函式的引數需要將string轉byte帶來的記憶體拷貝,
在改進版本writeheader1函式中通過斷言訪問行為(通過斷言判斷這個變數有沒有某個方法),來盡量避免呼叫write函式
*/// 假設這是乙個往http響應新增響應頭的函式
// w是乙個響應流,向這個響應流寫入的資料會傳送到客戶端
func
writeheader
(w io.writer, contenttype string
)error
return
nil}
func
writeheader1
(w io.writer, contenttype string
)error
return
nil}
/*其實 *os.file 有乙個 writestring 方法,這個方法可以直接往乙個檔案控制代碼中寫入字串,
這個方法會避免去分配乙個臨時的拷貝。
不僅是 *os.file,像 *bytes.buffer ,*bufio.writer 這些型別都有這個方法。
可是,我們不能保證所有的io.writer介面型別都有這個writestring方法。
*/func
writestring
(w io.writer, s string
)(n int
, err error
)// 通過斷言判斷w是否屬於ws這個介面,從而判斷w是否有writestring方法
if value, ok := w.
(ws)
; ok
// 如果w沒有writestring方法,那就只能呼叫write方法,就只能用byte轉型別了
return w.
write([
]byte
("content-type: "
+ s))}
func
testwriteheader
(t *testing.t)
我們知道非介面值的普通變數是不能進行斷言的。
其實只用將普通變數經過空介面轉為乙個介面值即可。
func
testtanointe***ce
(t *testing.t)
)(w)
.(io.writer)
// invalid type assertion: w.(io.writer) (non-inte***ce type *file on left)
//value, ok := w.(io.writer)
t.log
(value, reflect.
typeof
(value)
, ok)
}
或者
// 形參是x inte***ce{},當實參傳入就會自動將實參從普通變數轉換為介面值變數
func
isint
(x inte***ce
)bool
func
testtanointe***ce1
(t *testing.t)
到這裡基本上所有關於介面的知識已經介紹完畢。
最後是使用介面的一些建議:
介面不要濫用,不要隨便就建立乙個介面。
只有當有兩個或兩個以上的具體型別必須實現相同的方法時才去定義乙個介面。
例如 *os.file 和 *bytes.buffer 和 *bufio.writer都需要有乙個write方法,所以才有必要建立乙個io.writer介面來規範這三個型別。
?如果你也是【軟體工程師】,【關注❤️我】,一定會對你有所幫助。
?如果這篇文章對你有所幫助,那就麻煩,【點讚?】。
?您的支援將給與我更大的動力,謝謝?。
go語言學習筆記22 Go語言併發程式設計
goroutine是go語言並行設計的核心,有人稱之為go程。goroutine說到底其實就是協程,它比執行緒更小,十幾個goroutine可能體現在底層就是五六個執行緒,go語言內部幫你實現了這些goroutine之間的記憶體共享。執行goroutine只需極少的棧記憶體 大概是4 5kb 當然會...
Go語言型別轉換和型別斷言
型別轉換在編譯期完成,包括強制轉換和隱式轉換 型別斷言在執行時確定,包括安全型別斷言和非安全型別斷言 go語言要求不同型別之間必須做顯式的型別轉換。但似乎涉及到介面型別時,就會有所不同。兩種型別斷言 不安全的型別斷言,如果系統檢測到不匹配,會在執行時呼叫內建的panic,丟擲異常 s abc i s...
go語言的型別斷言 Type Assertion
x.t 檢查x的動態型別是否是t,其中x必須是介面值。如果t是具體型別 型別斷言檢查x的動態型別是否等於具體型別t。如果檢查成功,型別斷言返回的結果是x的動態值,其型別是t。換句話說,對介面值x斷言其動態型別是具體型別t,若成功則提取出x的具體值。如果檢查失敗則panic。例如 var w io.w...