免费爱碰视频在线观看,九九精品国产屋,欧美亚洲尤物久久精品,1024在线观看视频亚洲

      Go小知識(shí)新解

      Go接口實(shí)現(xiàn)中的的值接收者指針接收者

      1、值接收者和指針接收者

      所謂指針接收者和值接收者這兩個(gè)概念,用GO寫了一陣子代碼的人都了解了,這里只做簡要說明一下,也就是對(duì)于一個(gè)給定結(jié)構(gòu),咱們對(duì)結(jié)構(gòu)進(jìn)行方法包裝的時(shí)候,固定必傳的參數(shù),用來指向這個(gè)對(duì)象結(jié)構(gòu)自身的一個(gè)參數(shù),在go中也就是形式如下:

      type testStruct struct{a int}func (a testStruct)sum(x,y int)int { return a.a + x + y}func (a *testStruct)modify(v int) { a.a = v}

      我們對(duì)結(jié)構(gòu)體testStruct進(jìn)行了包裝,提供了兩個(gè)方法,sum和modify,其中sum的方法接收者為a testStruct,這個(gè)就是值接收者,而modify的接收者為a *testStruct就是指針接收者,也就是說固定對(duì)象指針,一個(gè)傳遞的是指針地址,而另外一個(gè)直接傳遞的是結(jié)構(gòu)值拷貝了

      對(duì)指針有一定了解的,都可以知道,指針傳遞過去的,可以直接修改結(jié)構(gòu)內(nèi)部內(nèi)容,而值傳遞過去的,無論如何修改這個(gè)接收者的數(shù)據(jù),不會(huì)對(duì)原對(duì)象結(jié)構(gòu)產(chǎn)生影響。而對(duì)于咱們包裝結(jié)構(gòu)對(duì)象的時(shí)候,到底是使用指針還是使用值接收者,這個(gè)實(shí)際上沒有太大的定論,就我個(gè)人的觀點(diǎn)來說,如果結(jié)構(gòu)體占有的內(nèi)存空間不大(<KB級(jí)別),而又不需要修改內(nèi)部的,同時(shí)結(jié)構(gòu)對(duì)象內(nèi)部沒有同步對(duì)象比如(sync包中的mutex,rwlock,waitGroup等之類的結(jié)構(gòu)的話,可以直接值傳遞,實(shí)際上值copy也沒有咱們想象的那么慢,很多時(shí)候,都用指針,最后的GC回收掃描可能都比咱們這個(gè)傳遞copy的消耗大)

      2、實(shí)現(xiàn)接口的值接收者和指針接收者有啥區(qū)別

      也就是比如定義如下

      type ITest interface { sum1(int, int) int}type ITest2 interface { sum2(int, int) int}type testStruct struct { a int}func (t testStruct) sum1(x, y int) int { return t.a + x + y}func (t *testStruct) sum2(x, y int) int { return t.a + x + y}

      這里面的值接收者和指針接收者有什么區(qū)別,這里咱來寫一個(gè)測(cè)試

      func main() { t := testStruct{ a: 3, } var test1 ITest var test2 ITest2 test2 = &t if v, ok := test2.(ITest); ok { fmt.Println(“指針接收者接口->值接收者接口”, v.sum1(5, 5)) } else { fmt.Println(“指針接收者接口 無法轉(zhuǎn)到 值接收者接口”) } test1 = t if v, ok := test1.(ITest2); ok { fmt.Println(“值接收者接口->指針接收者接口”, v.sum2(3, 3)) } else { fmt.Println(“值接收者接口 無法轉(zhuǎn)到 指針接收者接口”) }}

      通過這個(gè)測(cè)試用例可以發(fā)現(xiàn),指針接收者實(shí)現(xiàn)的接口可以同時(shí)支持轉(zhuǎn)移到值接收者接口和指針接收者接口,而用值接收者實(shí)現(xiàn)的接口,則無法轉(zhuǎn)移到使用指針接收者實(shí)現(xiàn)的接口,為啥子呢?目前網(wǎng)上或者各類資料上都是給的一個(gè)很官方很官方,而且很書面話難以理解的說明,大致意思如下:

      • 當(dāng)方法的接收者定義為值類型時(shí), Go 語言編譯器會(huì)自動(dòng)做轉(zhuǎn)換,所以值類型接收者和指針類型接收者是等價(jià)的,編譯不會(huì)報(bào)錯(cuò),運(yùn)行也都可以調(diào)用相應(yīng)方法
      • 在實(shí)現(xiàn)接口時(shí),應(yīng)保持接收者定義、結(jié)構(gòu)體定義、斷言類型一致

      這是目前網(wǎng)絡(luò)或者各種資料上都是差不多是這樣說的,看似講了,實(shí)際上就說了一個(gè)結(jié)果,根本就沒說出來一個(gè)為什么。這樣的總結(jié)出來,一個(gè)初學(xué)者的角度來看,是很不好理解的,初學(xué)者要么就是死記硬背,要么就是生搬硬套,甚至直到寫了好多好多代碼了,都還沒有搞明白一個(gè)為啥子,只是會(huì)用了而已,從長遠(yuǎn)來說這是不利于自身提高的。

      說了這么多,那么這到底是個(gè)什么原因呢,其實(shí)很簡單,我們關(guān)注其本質(zhì)就行了:

      • 值接收者是傳遞的時(shí)候,實(shí)際上是執(zhí)行了一個(gè)值拷貝傳遞進(jìn)去了,這個(gè)值拷貝和原數(shù)據(jù)已經(jīng)沒有任何關(guān)系了
      • 指針接收者傳遞的是地址,此時(shí)和原數(shù)據(jù)還有關(guān)聯(lián),通過解指針操作可以到原數(shù)據(jù)的數(shù)據(jù)空間

      有這兩個(gè)本質(zhì)點(diǎn),咱們自己來思考一下,如果你來實(shí)現(xiàn)這個(gè)編譯器的時(shí)候,用指針接收的時(shí)候,指針接收者,默認(rèn)就能直接獲取支持,而值接收者實(shí)現(xiàn)接口的咱們可以直接來一個(gè)解指針就變成了值,就能匹配上值接收者實(shí)現(xiàn)的接口了,反過來說,如果值接收者,此時(shí)要匹配指針接收者,如何匹配呢,取一個(gè)地址就變成了指針了,此時(shí)數(shù)據(jù)類型確實(shí)是匹配了,但是,地址指向的數(shù)據(jù)區(qū)不對(duì)了,因?yàn)槲覀儎倓傉f了值接收者拷貝了一個(gè)新值之后是完全的一個(gè)新的對(duì)象,這個(gè)新對(duì)象和原始對(duì)象一點(diǎn)關(guān)系都沒有,咱們?nèi)〉刂罚〉囊彩沁@個(gè)新對(duì)象地址,對(duì)這個(gè)地址進(jìn)行操作,也是這個(gè)新對(duì)象的內(nèi)部數(shù)據(jù),和原始數(shù)據(jù)內(nèi)部沒有任何關(guān)系,所以由此就能推斷出,這個(gè)是為啥子值接收者不能匹配上指針接收者,而指針接收者卻可以匹配上值接收者了。

      GO字符串小計(jì)

      1、在某個(gè)作用域內(nèi)部,所有定義的字符串的數(shù)據(jù)區(qū)相同

      這個(gè)很好驗(yàn)證,代碼如下:

      func main(){ tstr := “test1” data := (*reflect.StringHeader)(unsafe.Pointer(&tstr)) fmt.Println(“地址:”, data.Data) tstr2 := “test1” data = (*reflect.StringHeader)(unsafe.Pointer(&tstr2)) fmt.Println(“地址:”, data.Data)}

      2、字符串相加會(huì)產(chǎn)生一個(gè)新串

      這個(gè)也很好驗(yàn)證

      3、字符串真的是不可變的嗎

      實(shí)際上從字符串的結(jié)構(gòu)

      type stringStruct struct{Data uintptrlen int}

      從這個(gè)結(jié)構(gòu),就能大致的推斷出來,字符串設(shè)計(jì)成這樣就不具備直接擴(kuò)容+來增加新數(shù)據(jù),而如果咱們直接使用string[index] = ‘a’,用這種方式,就不能編譯通過,官方也確定說字符串是不可變的。那么真的是不可變的嗎?

      通過上面的結(jié)構(gòu),在加上go的slice切片的數(shù)據(jù)結(jié)構(gòu)

      type sliceStruct struct{Data uintptrlen intcap int}

      由此可見,咱們可以將字符串通過指針方式強(qiáng)轉(zhuǎn)為一個(gè)byte數(shù)組指針,然后通過byte切片來修改,試試

      func main() { tstr := “test1” data := (*reflect.StringHeader)(unsafe.Pointer(&tstr)) btHeader := reflect.SliceHeader{ Data: data.Data, Len: data.Len, Cap: data.Len, } bt := *(*[]byte)(unsafe.Pointer(&btHeader)) bt[0] = ‘a’}

      編譯通過,運(yùn)行報(bào)錯(cuò)

      unexpected fault address 0xae2e27fatal error: fault

      這個(gè)錯(cuò)誤,基本上就是一個(gè)內(nèi)存的保護(hù)錯(cuò)誤,是寫異常,所以說明了,這個(gè)肯定做了內(nèi)存寫保護(hù),那么直接修改一下內(nèi)存區(qū)的屬性,去掉他的寫保護(hù),就能寫了

      以下代碼都是在Win平臺(tái),Go1.18,Win上修改內(nèi)存權(quán)限屬性,使用VirtualProtect,代碼如下

      func main() { tstr := “test1” data := (*reflect.StringHeader)(unsafe.Pointer(&tstr)) btHeader := reflect.SliceHeader{ Data: data.Data, Len: data.Len, Cap: data.Len, } bt := *(*[]byte)(unsafe.Pointer(&btHeader)) kernelDell := syscall.NewLazyDLL(“kernel32.dll”) kernelDell.Load() VirtualProtect := kernelDell.NewProc(“VirtualProtect”) var old1 uint32 VirtualProtect.Call(uintptr(unsafe.Pointer(data.Data)), uintptr(data.Len), 0x40, uintptr(unsafe.Pointer(&old1))) bt[0] = ‘a’ bt[1] = ‘a’ fmt.Println(tstr)}

      此時(shí)運(yùn)行,就能發(fā)現(xiàn)tstr的內(nèi)容被咱們變了,這種情況實(shí)際上在實(shí)際開發(fā)中不具有實(shí)際意義,因?yàn)楸旧碓谡Z言層面,已經(jīng)做了層層限制,咱們這是屬于非法強(qiáng)制的操作方式,是流氓行為,那么是否有比較溫和一點(diǎn)的操作方式呢?答案是有的,且往下看。

      通過上面,我們已經(jīng)用到了字符串結(jié)構(gòu),切片結(jié)構(gòu),要想字符串內(nèi)容可變,那么咱們自己構(gòu)造字符串的數(shù)據(jù)內(nèi)容區(qū)域,且讓這個(gè)數(shù)據(jù)區(qū)木有內(nèi)存寫保護(hù)不就行了,內(nèi)容區(qū)可變,GO原生態(tài)的byte數(shù)組不就行嘛,所以咱們自己構(gòu)造一下

      func main() { buffer := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0} stringData := reflect.StringHeader{ Data: uintptr(unsafe.Pointer(&buffer[0])), Len: len(buffer),} buffer[0] = ‘h’ buffer[1] = ‘e’ buffer[2] = ‘l’ buffer[3] = ‘l’ buffer[4] = ‘o’ buffer[5] = ‘ ‘ buffer[6] = ‘w’ buffer[7] = ‘o’ buffer[8] = ‘r’ str := *(*string)(unsafe.Pointer(&stringData)) fmt.Println(str)}

      此時(shí)我們直接修改buffer的內(nèi)容,就是直接修改了str的數(shù)據(jù)內(nèi)容了。而又不會(huì)像前面的一樣遇到內(nèi)存寫保護(hù)

      4、字符串轉(zhuǎn)換優(yōu)化時(shí)可能碰到的坑

      通過前面討論的字符串的可變性的方法,咱們可以知道,很多時(shí)候,[]byte到字符串的轉(zhuǎn)變,可以直接構(gòu)造其結(jié)構(gòu),而共享數(shù)據(jù),從而達(dá)到減少數(shù)據(jù)內(nèi)存copy的方式來進(jìn)行優(yōu)化,再使用這些優(yōu)化的時(shí)候,一定需要注意,字符串或者數(shù)組的生命周期,是否會(huì)存在被改寫的情況,從而導(dǎo)致前后不一致的問題。

      比如下面這段代碼:

      func main() { buffer := []byte(“test”) stringData := reflect.StringHeader{ Data: uintptr(unsafe.Pointer(&buffer[0])), Len: len(buffer), } str := *(*string)(unsafe.Pointer(&stringData)) mmp := make(map[string]int, 32) mmp[str] = 3 mmp[“abcd”] = 4 fmt.Println(mmp[str]) buffer[0] = ‘a’ buffer[1] = ‘b’ buffer[2] = ‘c’ buffer[3] = ‘d’ fmt.Println(mmp[str]) fmt.Println(mmp[“test”]) fmt.Println(mmp[“abcd”]) for k, v := range mmp { fmt.Println(k, v) }}

      大家可以猜想一下,這個(gè)最后里面的數(shù)據(jù)mmp中,”test”的value是多少,”abcd”的value是多少,然后想想為什么,且等端午之后,再來分解

      鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場,版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員(admin#wlmqw.com)刪除。
      (0)
      用戶投稿
      上一篇 2022年7月1日 02:45
      下一篇 2022年7月1日 02:45

      相關(guān)推薦

      • 夜雨丨周成芳:父親的詩意人生

        父親的詩意人生 周成芳 父親不是詩人,可他骨子里卻充滿詩情畫意。 我小時(shí)候,父親在安徽鐵路局工作,母親在家?guī)е齻€(gè)孩子。那時(shí)候沒有手機(jī)網(wǎng)絡(luò),親人之間常見的聯(lián)系方式就是書信。 “程姐…

        2022年7月17日
      • 內(nèi)存數(shù)據(jù)庫

        內(nèi)存數(shù)據(jù)庫從范型上可以分為關(guān)系型內(nèi)存數(shù)據(jù)庫和鍵值型內(nèi)存數(shù)據(jù)庫。 在實(shí)際應(yīng)用中內(nèi)存數(shù)據(jù)庫主要是配合oracle或mysql等大型關(guān)系數(shù)據(jù)庫使用,關(guān)注性能。 作用類似于緩存,并不注重?cái)?shù)…

        2022年6月19日
      • pytest接口自動(dòng)化測(cè)試框架 – pytest結(jié)合二次封裝實(shí)現(xiàn)接口自動(dòng)化

        視頻來源:B站《冒死上傳!pytest接口自動(dòng)化測(cè)試框架(基礎(chǔ)理論到項(xiàng)目實(shí)戰(zhàn)及二次開發(fā))教學(xué)視頻【軟件測(cè)試】》 一邊學(xué)習(xí)一邊整理老師的課程內(nèi)容及試驗(yàn)筆記,并與大家分享,侵權(quán)即刪,謝…

        2022年7月16日
      • 奇安信成立新公司 經(jīng)營范圍含區(qū)塊鏈技術(shù)相關(guān)軟件和服務(wù)

        企查查APP顯示,7月14日,黑龍江奇安信科技有限公司成立,注冊(cè)資本1500萬元,經(jīng)營范圍包含網(wǎng)絡(luò)與信息安全軟件開發(fā);區(qū)塊鏈技術(shù)相關(guān)軟件和服務(wù);計(jì)算機(jī)系統(tǒng)服務(wù);信息安全設(shè)備銷售;互…

        2022年7月16日
      • 國防科大“天河”超算斬獲兩項(xiàng)世界第一

        湖南日?qǐng)?bào)6月24日訊(全媒體記者 施泉江 通訊員 高莉華)近日,記者從國防科技大學(xué)計(jì)算機(jī)學(xué)院獲悉,在第24屆國際超算排名Graph500發(fā)布的榜單中,由該院研制并部署在國家超級(jí)計(jì)算…

        2022年6月25日
      • 腰椎間盤突出開始折磨年輕人了 患者已突破2億人

        據(jù)國家衛(wèi)生健康委公布的數(shù)據(jù),目前中國腰椎病患者已突破2億人,發(fā)病率僅次于感冒,成年人腰椎病發(fā)病率為80%。值得注意的是,腰椎間盤突出開始折磨年輕人了。下面,我們一起來具體了解一下吧…

        2022年10月7日
      • 12.5米DEM免費(fèi)下載教程、土地利用數(shù)據(jù)、植被類型分布數(shù)據(jù)

        ALOS是日本在2006年1月發(fā)射的對(duì)地觀測(cè)衛(wèi)星,在2011年的時(shí)候因?yàn)殡娏Ξ惓6ネㄓ嵞芰?。ALOS衛(wèi)星載有三個(gè)傳感器:全色遙感立體測(cè)繪儀(PRISM),主要用于數(shù)字高程測(cè)繪;…

        2022年8月16日
      • 陳尊佑生母之謎:被懷疑對(duì)象均是絕色女星,20年后都已組建家庭

        因?yàn)椤讹L(fēng)起隴西》口碑的崩壞,導(dǎo)致陳坤再次成為熱點(diǎn)話題,而關(guān)于他之前為內(nèi)娛圈貢獻(xiàn)的“未解之謎”,也再次成為大眾關(guān)注的焦點(diǎn)。 如今,陳坤的兒子陳尊佑已滿20周歲,是個(gè)被粉絲稱為“高級(jí)臉…

        2022年5月12日
      • linux系統(tǒng)中什么是系統(tǒng)調(diào)用?

        linux中什么是系統(tǒng)調(diào)用 1.什么是系統(tǒng)調(diào)用 系統(tǒng)調(diào)用,指的是操作系統(tǒng)提供給用戶程序調(diào)用的一組特殊接口,用戶程序可以根據(jù)這組接口獲得操作系統(tǒng)內(nèi)核的服務(wù)。它規(guī)定了用戶進(jìn)程陷入內(nèi)核的…

        2022年6月21日
      • 最強(qiáng)購機(jī)攻略!8月最值得購買的2-3K價(jià)位手機(jī)推薦,附手機(jī)選購指南

        暑假已經(jīng)過半,馬上進(jìn)入8月,相信很多有購機(jī)欲望的小伙伴還在糾結(jié),不知道該選擇哪款手機(jī),希望這篇文章可以幫助到你,我們將回顧2022年至今發(fā)布的所有新手機(jī),匯總并為你推薦兩千到三千價(jià)…

        2022年8月1日

      聯(lián)系我們

      聯(lián)系郵箱:admin#wlmqw.com
      工作時(shí)間:周一至周五,10:30-18:30,節(jié)假日休息