interface:不限定類(lèi)型叫惊,只關(guān)注方法!
? 這是它的優(yōu)點(diǎn)做修,因?yàn)榫幾g器在編譯時(shí)不去確定你傳的到底是什么類(lèi)型霍狰,你傳一個(gè)string,它能接收饰及,你傳一個(gè)對(duì)象struct蔗坯,它也能接收,它只有一個(gè)要求燎含,實(shí)現(xiàn)我要求實(shí)現(xiàn)的方法宾濒!
? 既然interface是不限定類(lèi)型,是通用類(lèi)型瘫镇,這是一種開(kāi)放表現(xiàn)鼎兽,這種開(kāi)放怎么實(shí)現(xiàn)的呢?方法就是不去檢驗(yàn)?zāi)愕念?lèi)型铣除,既然不檢驗(yàn)?zāi)且膊蝗ビ涗浤愕念?lèi)型Q枰А!I姓场择卦!注意interface不記錄你的類(lèi)型,所以不管你是string郎嫁,struct秉继,int,我都不管泽铛,我都不記錄尚辑,我只記錄你的地址,結(jié)果是編譯器在編譯時(shí)也不知道你是什么類(lèi)型盔腔,你有什么字段杠茬!
? 但是現(xiàn)在有一個(gè)問(wèn)題,編譯器也沒(méi)辦法確定一個(gè)interface以前是什么類(lèi)型3谒妗(編譯時(shí))這就是因果關(guān)系:為了達(dá)到通用瓢喉,interface不做確定工作,結(jié)果就是interface也不知道以前的類(lèi)型舀透。
? 一個(gè)類(lèi)型轉(zhuǎn)接口的過(guò)程栓票,就是放棄自我類(lèi)型的過(guò)程,變成了沒(méi)有類(lèi)型愕够。
優(yōu)點(diǎn)
這樣做有什么好處呢走贪,很顯然是:通用佛猛,如果把一個(gè)函數(shù)的傳入?yún)?shù)設(shè)置為空接口(interface{}),那么任何類(lèi)型當(dāng)做參數(shù)都能夠調(diào)用該接口厉斟,最好的例子就是:
fmt.println(i interface{})
它就是一個(gè)很標(biāo)準(zhǔn)的例子挚躯,println傳入?yún)?shù)可以是任何類(lèi)型,都能打印出它的值擦秽。
當(dāng)一個(gè)類(lèi)型轉(zhuǎn)換成interface以后码荔,怎么確定它原來(lái)的類(lèi)型?
? 當(dāng)然你可以說(shuō)你記得感挥,因?yàn)槭悄惆阉D(zhuǎn)換成interface缩搅,你理所當(dāng)然的記得,可編譯器不知道啊触幼,interface不包含類(lèi)型硼瓣,也就是說(shuō)你沒(méi)有讓它去記錄,所以它不知道置谦。
? 針對(duì)這個(gè)問(wèn)題堂鲤,go語(yǔ)言給了一個(gè)解決方案,斷言媒峡,當(dāng)將一個(gè)interface轉(zhuǎn)換成它原來(lái)類(lèi)型的時(shí)候瘟栖,在它后面指明它的原來(lái)類(lèi)型,這樣編譯器就知道該按照什么類(lèi)型去解析了谅阿。(其實(shí)說(shuō)白了半哟,這就是通過(guò)人的記憶,編譯器不知道是什么類(lèi)型签餐,你告訴編譯器就可以了)
? 斷言其實(shí)是先獲取interface的動(dòng)態(tài)類(lèi)型寓涨,然后與你指定的類(lèi)型做判斷,如果一致氯檐,將它轉(zhuǎn)換成你指定的類(lèi)型戒良。如果不知道動(dòng)態(tài)類(lèi)型,可以看這篇文章:https://segmentfault.com/a/1190000012372372
不加斷言
// string type
var s string= "sss"
// interface type
var a interface{}
a = s
//convert to string
var ss string
ss = a // 不加斷言
fmt.Println(ss)
# command-line-arguments
.\exe_time.go:18:5: cannot use a (type interface {}) as type string in assignment: need type assertion
從報(bào)錯(cuò)可以看出冠摄, 不能直接轉(zhuǎn)換糯崎,需要對(duì)接口先進(jìn)行斷言
ss = a.(string)
如何對(duì)interface內(nèi)的數(shù)據(jù)進(jìn)行修改
? 通常情況下,一個(gè)變量在確定類(lèi)型的情況下編譯器知道他有哪些功能(注意耗拓,這里是針對(duì)編譯時(shí))拇颅,比如一個(gè)int類(lèi)型奏司,編譯器在編譯時(shí)知道能對(duì)他加減int乔询,不能加減float,如果你這么做我就給你報(bào)錯(cuò)韵洋。一個(gè)struct包含哪些字段竿刁,不包含哪些字段黄锤,我定義一個(gè)user結(jié)構(gòu)體,里面只有name和age兩個(gè)字段食拜,那么你只能取我這兩字段的值鸵熟,你如果取height,我就給你報(bào)錯(cuò)负甸。
? 這些都是正常情況下的流强,但是對(duì)于一個(gè)接口呢,編譯器會(huì)變成瞎子呻待!在編譯的時(shí)候它不知道你原來(lái)是什么類(lèi)型打月,所以它也沒(méi)法確定你包含什么字段,同樣是之前那個(gè)user結(jié)構(gòu)體蚕捉,當(dāng)把它轉(zhuǎn)換成接口以后奏篙,編譯器就對(duì)它的類(lèi)型一無(wú)所知了,你獲取name字段迫淹,這有接口有沒(méi)有呢秘通?編譯器不知道!你請(qǐng)求height字段敛熬,這個(gè)泛型有沒(méi)有呢肺稀?編譯器仍然不知道。所以你編譯時(shí)不能修改接口里的數(shù)據(jù)荸型,既然編譯時(shí) 不能修改盹靴,那就只能在運(yùn)行時(shí)修改了。
? 這個(gè)時(shí)候就該反射登場(chǎng)了瑞妇,它能夠在運(yùn)行時(shí)修改接口的數(shù)據(jù)稿静,通過(guò)追根溯源,獲取接口底層的實(shí)際數(shù)據(jù)和類(lèi)型辕狰,讓你能夠?qū)涌诘脑磾?shù)據(jù)進(jìn)行操作改备。
? 換一種大白話(huà)的說(shuō)法,反射就是刨根問(wèn)底蔓倍,獲取這個(gè)接口究竟是怎么產(chǎn)生的悬钳,因?yàn)槟呐乱粋€(gè)類(lèi)型轉(zhuǎn)變成接口時(shí)放棄了自己的類(lèi)型,但是它的本質(zhì)不會(huì)變的偶翅,就像趙本山的小品里所說(shuō):小樣默勾,別以為你脫掉馬甲我就不認(rèn)識(shí)你了!對(duì)聚谁,它的底層里仍然存儲(chǔ)了它的數(shù)據(jù)類(lèi)型母剥,只是藏的比較深,一般手段拿不到,但我們?nèi)匀荒軌蛲ㄟ^(guò)反射(這個(gè)包根問(wèn)底的工具)來(lái)確定你究竟包含哪些字段和值环疼,確定你究竟是蛇還是脫了馬甲的烏龜习霹!