日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

雖然在上篇文章中,我們通過嘗試性學(xué)習(xí)探索了 Go 語言中關(guān)于面向?qū)ο蟮南嚓P(guān)概念,更確切的說是關(guān)于封裝的基本概念以及相關(guān)實(shí)現(xiàn).

但那還遠(yuǎn)遠(yuǎn)不夠,不能滿足于一條路,而是應(yīng)該盡可能地多走幾條路,只有這樣才能為以后可能遇到的問題積攢下來經(jīng)驗(yàn),所以這一節(jié)我們將繼續(xù)探索封裝.

何為探索性學(xué)習(xí)

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

通過現(xiàn)有知識(shí)加上思想規(guī)則指導(dǎo)不斷猜想假設(shè)逐步驗(yàn)證的學(xué)習(xí)過程是探索性學(xué)習(xí),這樣既有利于我們思考又能加深我們對(duì)新知識(shí)的理解,何樂而不為?

學(xué)習(xí) Go 語言的過程越發(fā)覺得吃力,倒不是因?yàn)檎Z法晦澀難懂而是因?yàn)檎Z法習(xí)慣背后蘊(yùn)藏的思維習(xí)慣差異性太大!

Go 語言相對(duì)于其他主流的編程語言來說是一種新語言,不僅體現(xiàn)在語法層面更重要的是實(shí)現(xiàn)思路的差異性.

尤其是對(duì)于已有其他編程經(jīng)驗(yàn)的開發(fā)者而言,這種體會(huì)更加深刻,原本可能覺得理所應(yīng)當(dāng)?shù)氖虑榈搅?Go 語言這里基本上都變了模樣,很大程度上都換了一種思路去實(shí)現(xiàn),這其實(shí)是一件好事,不同的思維碰撞才能促進(jìn)思考進(jìn)步,一成不變的話,談何創(chuàng)新發(fā)展?

在這里不得不感謝強(qiáng)大的 IDE 開發(fā)工具,沒有它我們就不能及時(shí)發(fā)現(xiàn)錯(cuò)誤,正是這種快速試錯(cuò)的體驗(yàn)才給我們足夠的反饋,運(yùn)用已有的編程經(jīng)驗(yàn)逐步接近 Go 語言編程的真相.

上篇文章中已經(jīng)確定主線方向,基本上弄清楚了面向?qū)ο笾械姆庋b概念以及實(shí)現(xiàn),為了不遺漏任何可能重要的知識(shí)點(diǎn),本文將繼續(xù)開放性探索,力爭(zhēng)講解清楚封裝的知識(shí)點(diǎn).

如果這種學(xué)習(xí)的過程用走迷宮來比喻的話,一條道走到黑這種策略就是算法理論中的深度優(yōu)先算法.如果邊走邊看,四處觀望周圍的風(fēng)景就是廣度優(yōu)先算法.

所以,聰明的你肯定已經(jīng)猜到了,上文采用的正是深度優(yōu)先算法而本文則采用廣度優(yōu)先算法繼續(xù)探索封裝對(duì)象之旅!

定義結(jié)構(gòu)體

結(jié)構(gòu)體的定義方式只有一種,或者不存在簡(jiǎn)化形式嗎?

個(gè)人覺得不會(huì)不存在簡(jiǎn)化形式,當(dāng)結(jié)構(gòu)體存在多個(gè)字段,標(biāo)準(zhǔn)定義方式是合理使用的,但要是字段只有一個(gè),仍然以標(biāo)準(zhǔn)形式定義結(jié)構(gòu)體未免有種殺雞焉用牛刀的感覺.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

所謂的結(jié)構(gòu)體只不過是實(shí)現(xiàn)封裝的一種手段,當(dāng)封裝的對(duì)象只有一個(gè)字段時(shí),這個(gè)字段也就不存在字段名或者說這個(gè)唯一的字段名應(yīng)該就可以由編譯器自動(dòng)定義,因此字段名可以省略.

字段類型肯定是不可或缺的,這么想的話,對(duì)于封裝只有一個(gè)字段的對(duì)象來說,只需要考慮的是這個(gè)唯一字段的類型.

基于上述原因,個(gè)人覺得是這種猜想是合情合理的,但是按照已有的知識(shí)能否實(shí)現(xiàn)呢?

簡(jiǎn)單起見,暫時(shí)先以上篇文章中關(guān)于動(dòng)態(tài)數(shù)組的結(jié)構(gòu)體聲明為例作為測(cè)試案例.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

如果一定要從三個(gè)字段中選擇一個(gè)字段,那只能是保留內(nèi)部數(shù)組,排除其余字段了,同時(shí)最終結(jié)果上可能實(shí)現(xiàn)不了動(dòng)態(tài)數(shù)組的功能,語義上會(huì)有所欠缺,那就不論語義,只談技術(shù)!

由于只保留內(nèi)部數(shù)組,動(dòng)態(tài)數(shù)組就變成下面這樣.失去了動(dòng)態(tài)數(shù)組的語義,命名上也做了改變,姑且稱之為 MyArray 吧!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

很明顯,現(xiàn)在仍然是結(jié)構(gòu)體的標(biāo)準(zhǔn)語法形式,請(qǐng)隨我一起思考一下如何簡(jiǎn)化這種形式?

因?yàn)檫@種簡(jiǎn)化形式的內(nèi)部字段只有一個(gè),所以字段名必須省略而字段類型可能不同,因此應(yīng)該在簡(jiǎn)化形式中只保留聲明內(nèi)部字段類型的部分.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

由于多個(gè)字段時(shí)才需要換行分隔,一個(gè)字段自然是不需要換行的,因此大括號(hào)也是沒必要存在的,這也是符合 Go 設(shè)計(jì)中盡可能精簡(jiǎn)的情況下保證語義清晰的原則.

當(dāng)然如果你問我是否真的有這個(gè)原則的話,我的回答是可能有也可能沒有.

因?yàn)槲乙膊恢?只是近期學(xué)習(xí) Go 語言的一種感覺,處處體現(xiàn)了這么一種哲學(xué)思想,也不用較真,只是個(gè)人看法.

type MyArray struct [10]int

現(xiàn)在這種形式應(yīng)該可以算是只有一種字段的結(jié)構(gòu)體的簡(jiǎn)化形式,struct 語義上指明了 MyArray 是結(jié)構(gòu)體,緊隨后面的 [10]int 語義上表示結(jié)構(gòu)體的類型,整體上就是說 MyArray 結(jié)構(gòu)體的類型是 [10]int .

現(xiàn)在讓我們?cè)诰庉嬈髦袦y(cè)試一下,看一看 Go 的編譯會(huì)不會(huì)報(bào)錯(cuò),能否驗(yàn)證我們的猜測(cè)呢?

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

很遺憾,IDE 編輯器告訴我們 [10]int 不合法,必須是類型或類型指針!

可 [10]int 確實(shí)是我們需要的類型啊,既然報(bào)錯(cuò)也就是說Go 編譯器不支持這種簡(jiǎn)化形式!

個(gè)人猜測(cè)可能是 struct 關(guān)鍵字不支持這種簡(jiǎn)化形式,那就去掉這個(gè)關(guān)鍵字好了!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

沒想到真的可以!

至少現(xiàn)在看來 Go 編譯器是支持簡(jiǎn)化形式的,至于這種支持的形式和我們預(yù)期實(shí)現(xiàn)的語義是否一致,暫時(shí)還不好說,繼續(xù)做實(shí)驗(yàn)探索吧!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

通過聲明變量后直接打印,初步證明了我們這種簡(jiǎn)化形式是可以正常工作的,輸出結(jié)果也是我們定義的內(nèi)部數(shù)組!

接下來看一看能不能對(duì)這個(gè)所謂的內(nèi)部數(shù)組進(jìn)行操作呢?

這種簡(jiǎn)化形式只有一個(gè)字段,只指明了字段的類型,沒有字段名,因而訪問該字段應(yīng)該直接通過結(jié)構(gòu)體變量訪問,不知道這種猜測(cè)是否正確,依舊做實(shí)驗(yàn)來證明.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

這一次猜想也得到了驗(yàn)證,Go 編譯器就是通過結(jié)構(gòu)體變量直接操作內(nèi)部字段,看來我們離真相更進(jìn)一步!

先別急著高興,將唯一的字段換成其他類型,多測(cè)試幾遍看看是否依然正常?

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

一番測(cè)試后并沒有報(bào)錯(cuò),很有可能這是 Go 所支持的結(jié)構(gòu)體簡(jiǎn)化形式,也和我們的預(yù)期一致.

關(guān)于結(jié)構(gòu)體屬性的語法規(guī)則暫時(shí)沒有其他探索的新角度,接下來開始探索結(jié)構(gòu)體的方法.

探索的過程中要盡可能的設(shè)身處地思考 Go 語言應(yīng)該如何設(shè)計(jì)才能方便使用者,盡可能地把自己想象成 Go 語言的設(shè)計(jì)者!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

結(jié)構(gòu)體的簡(jiǎn)化形式下可能并不支持方法,如果真的是這樣的話,這樣做也有一定道理.

首先就語法層面分析,為什么單字段的結(jié)構(gòu)體不支持方法?

還記得我們想要簡(jiǎn)化單字段結(jié)構(gòu)體遇到的報(bào)錯(cuò)提示嗎?

type MyArray struct [10]int

如果直接將單字段類型放到 struct 關(guān)鍵字后面,Go 編譯器就會(huì)報(bào)錯(cuò),當(dāng)我們省略 struct 關(guān)鍵字時(shí)上述報(bào)錯(cuò)自然就消失了.

從Go 編譯器的角度上來講,struct 是系統(tǒng)關(guān)鍵字,告訴編譯器只要遇到這個(gè)關(guān)鍵字就解析成結(jié)構(gòu)體語法,現(xiàn)在沒有遇到 sruct 關(guān)鍵字也就意味著不是結(jié)構(gòu)體語法.

這里關(guān)鍵字和結(jié)構(gòu)體是一一對(duì)應(yīng)關(guān)系,也就是充分必要條件,由關(guān)鍵字可以推測(cè)到結(jié)構(gòu)體,由結(jié)構(gòu)體也可以推測(cè)到關(guān)鍵字.

再回來看一看,我們的單字段結(jié)構(gòu)體是怎么定義的呢?

type MyArray [10]int

因?yàn)闆]有關(guān)鍵字 struct ,所以編譯器推斷 MyArray 不是結(jié)構(gòu)體,既然不是結(jié)構(gòu)體,也不能用結(jié)構(gòu)體的接收者函數(shù)去定義方法.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

所以這種方法就會(huì)報(bào)錯(cuò),由此可見 ,Go 語言如果真的不支持單字段結(jié)構(gòu)體方法也有理可循.

然后我們?cè)購恼Z義的角度上解釋一下為什么不支持方法?

回到探索的初衷,當(dāng)正在定義的結(jié)構(gòu)體有多個(gè)字段時(shí),應(yīng)該按照標(biāo)準(zhǔn)寫法為每個(gè)字段指定字段的名稱和類型.

假如該字段有且只有一個(gè)時(shí),再按照標(biāo)準(zhǔn)寫法定義當(dāng)然可以,但也應(yīng)該提供更加簡(jiǎn)化的寫法.

只有一個(gè)字段的結(jié)構(gòu)體,字段名稱是沒有意義的也是不應(yīng)該出現(xiàn)的,因?yàn)橥耆梢杂媒Y(jié)構(gòu)體變量所代替,此時(shí)這個(gè)結(jié)構(gòu)體唯一有存在價(jià)值的就是字段的類型了!

字段類型包括內(nèi)建類型和用戶自定義結(jié)構(gòu)體類型,不論哪種類型,這種簡(jiǎn)化形式的結(jié)構(gòu)體的語義上完全可以由該結(jié)構(gòu)體的字段類型所決定,所以簡(jiǎn)化形式的結(jié)構(gòu)體還需要方法嗎?

自然是不需要的!

字段類型可以由字段類型自己定義的,也能確保職責(zé)清晰,彼此分離!

綜上,個(gè)人覺得即便 Go 真的不支持單字段結(jié)構(gòu)體的方法,背后的設(shè)計(jì)還是有章可循的,有理可依的!

上文中定義動(dòng)態(tài)數(shù)組時(shí),內(nèi)部使用的數(shù)組是靜態(tài)數(shù)組,現(xiàn)在為了方便繼續(xù)探索方法,應(yīng)該提供重載方法使其支持動(dòng)態(tài)數(shù)組.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

內(nèi)部數(shù)組 arr 是靜態(tài)數(shù)組,應(yīng)該提供可以讓外部調(diào)用者初始化指定數(shù)組的接口,按照已知的面向?qū)ο笾嘘P(guān)于方法的定義來重載方法.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

初次嘗試方法的重載就遇到了問題,報(bào)錯(cuò)提示該方法已聲明,所以說 Go 可能并不支持方法重載,這樣就有點(diǎn)麻煩了.

想要實(shí)現(xiàn)類似的功能要么通過定義不同的方法名,要么定義一個(gè)非常大的函數(shù),接收最全的參數(shù),再根據(jù)調(diào)用者參數(shù)進(jìn)行對(duì)應(yīng)的邏輯處理.

用慣了方法的重載,突然發(fā)現(xiàn)這種特性在 Go 語言中無法實(shí)現(xiàn),頓時(shí)有點(diǎn)沮喪,和其他主流的面向?qū)ο笳Z言差異性也太大了吧!

不支持構(gòu)造函數(shù),不支持方法重載,原來以為理所應(yīng)當(dāng)?shù)奶匦圆⒉焕硭鶓?yīng)當(dāng).

還是先冷靜下來想一想,Go 為什么不支持方法重載呢?難不成和構(gòu)造函數(shù)那樣,怕是濫用干脆禁用的邏輯?

因?yàn)槲也皇窃O(shè)計(jì)者,無法體會(huì)也不想猜測(cè)原因,但可以肯定的是,Go 語言是一門全新的語言,有著獨(dú)特的設(shè)計(jì)思路,不與眾人同!

吐槽時(shí)間結(jié)束,既然上了賊船就得一條道走到黑,不支持方法重載就換個(gè)函數(shù)名或者按參數(shù)名區(qū)分.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

天啊擼,剛剛解決方法重載問題又冒出數(shù)組初始化不能是變量只能是常量表達(dá)式?

簡(jiǎn)直不可思議!

既然數(shù)組初始化長度只是常量表達(dá)式,也就無法接收外部傳遞的容量 cap,沒有了容量只能接收長度 len ,而初始化內(nèi)部數(shù)組長度又沒辦法確定了,兩個(gè)變量都無法對(duì)外暴露!

一切又回到原點(diǎn),想要實(shí)現(xiàn)動(dòng)態(tài)數(shù)組的功能只能靠具體的方法中去動(dòng)態(tài)擴(kuò)容和縮容,不能初始化指定長度了.

這樣的話,關(guān)于方法也是一條死路,停止探索.

聲明結(jié)構(gòu)體

結(jié)構(gòu)體定義基本已經(jīng)探索完畢,除了發(fā)現(xiàn)一種單字段結(jié)構(gòu)體的簡(jiǎn)化形式外,暫時(shí)沒有新的發(fā)現(xiàn).

再次回到使用者的角度上,聲明結(jié)構(gòu)體有沒有其他方式呢?

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

這是變量的聲明方式,除了這種形式,還記得在學(xué)習(xí) Go 的變量時(shí)曾經(jīng)介紹過聲明并初始化變量方式,是否也適用于結(jié)構(gòu)體變量呢?

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

編譯器沒有報(bào)錯(cuò),證明這種字面量形式也是適用的,不過空數(shù)據(jù)結(jié)構(gòu)沒有太大的意義,怎么能初始化對(duì)應(yīng)的結(jié)構(gòu)呢?

和多字段結(jié)構(gòu)體最為相似的數(shù)據(jù)結(jié)構(gòu)莫過于映射 map 了!

回憶一下 map 如何進(jìn)行字面量初始化的吧!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

模仿這種結(jié)構(gòu)看看能不能對(duì)結(jié)構(gòu)體也這么初始化,果然就沒有那么順利!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

我還沒定義,你就不行了?

IDE 編輯器提示字段名稱無效,結(jié)構(gòu)體明明就有 len 字段啊,除非是沒有正確識(shí)別!

"len" 與 len 是不一樣的吧?

那就去掉雙引號(hào) "" 直接使用字段名進(jìn)行定義看看.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

此時(shí)報(bào)錯(cuò)消失了,成功解鎖一種新的隱藏技能.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

除了這種指定字段名稱注入方式,能不能不指定字段名稱而是按照字段順序依次初始化?

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

借助編輯器可以看到確實(shí)是按照順序注入的,這樣的話,其實(shí)有點(diǎn)意思了,明明不支持構(gòu)造函數(shù),采用字面量實(shí)例化時(shí)卻看起來像構(gòu)造函數(shù)的無參,有參數(shù)和全參形式?

可以預(yù)想到的是,這種全參注入的方式一定是嚴(yán)格按照定義順序相匹配的,當(dāng)參數(shù)不全時(shí)可能按位插入也可能不支持,真相如何,一試便知!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

事實(shí)上并不支持這種參數(shù)不全的形式,因此個(gè)人覺得要么無參要么全參要么指定初始化字段這三種語義上還是比較清楚的.

除了字面量的方式,Go 是否支持創(chuàng)建 slice 或 map 時(shí)所使用的 make 函數(shù)呢?

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

看樣子,make 函數(shù)并不支持創(chuàng)建結(jié)構(gòu)體,至于為什么不支持,原因就不清楚了,也是個(gè)人的一個(gè)疑惑點(diǎn).

既然 make 可以創(chuàng)建 slice ,map 這種內(nèi)建類型,語義上就是用來創(chuàng)建類型的變量,而結(jié)構(gòu)體也是一種類型,唯一的差別可能就是結(jié)構(gòu)體大多是自定義類型而不是內(nèi)建類型.

如果我來設(shè)計(jì)的話,可能會(huì)一統(tǒng)天下,因?yàn)檎Z義上一致的功能只使用相同的關(guān)鍵字.

回到面向?qū)ο蟮膫鹘y(tǒng)編程規(guī)范上,一般實(shí)例化對(duì)象用的是關(guān)鍵字 new,而 new 并不是 Go 中的關(guān)鍵字.

Go 語言中的函數(shù)是一等公民,正如剛才說的 make 也不是關(guān)鍵字,同樣是函數(shù).

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

即便對(duì)于同一個(gè)目標(biāo),Go 也是有著自己的獨(dú)到見解!

new 不是以關(guān)鍵字形式出現(xiàn)而是以函數(shù)的身份登場(chǎng),初步推測(cè)應(yīng)該也具備實(shí)例化對(duì)象的能力吧?

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

難道 new 函數(shù)不能實(shí)例化對(duì)象?為什么報(bào)錯(cuò)說賦值錯(cuò)誤,難不成姿勢(shì)不對(duì)?

嚇得我趕緊看一下 new 的文檔注釋.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

根據(jù)注釋說明,果然是使用姿勢(shì)不對(duì),并不像其他的面向?qū)ο笳Z言那樣可以重復(fù)賦值,Go 不支持這種形式,還是老老實(shí)實(shí)初始化聲明吧!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

既然存在著兩種方式來實(shí)例化對(duì)象,那么總要看一下有什么區(qū)別.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 


go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

這里簡(jiǎn)單解釋下 t.Logf("%[1]T %[1]v", myDynamicArray) 語句是什么意思?

%[1]T 其實(shí)是 %T 的變體,%[1]v 也是 %v 的變體,仔細(xì)觀察的話就會(huì)發(fā)現(xiàn)占位符剛好都是同一個(gè)變量,這里也就是第一個(gè)參數(shù),所以就用 [1] 替代了,再次體現(xiàn)了 Go 語言設(shè)計(jì)的簡(jiǎn)潔性.

下面再舉一個(gè)簡(jiǎn)單的例子加深印象,看仔細(xì)了哦!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

%T 是打印變量的類型,應(yīng)該是類型 type 的縮寫,v 應(yīng)該是值 value 的縮寫.

解釋清楚了測(cè)試代碼的含義,再回頭看看測(cè)試結(jié)果,發(fā)現(xiàn)采用字面量方式得到的變量類型和 new 函數(shù)得到的變量類型明顯不同!

具體表現(xiàn)為 _struct.MyDynamicArray {0xc0000560f0 10 10} 是結(jié)構(gòu)體類型,而 *_struct.MyDynamicArray &{0xc000056190 10 10} 是結(jié)構(gòu)體類型的指針類型.

這種差異也是可以預(yù)期的差異,也是符合語義的差異.

字面量實(shí)例化的對(duì)象是值對(duì)象,而 new 實(shí)例化對(duì)象開辟了內(nèi)存,返回的是實(shí)例對(duì)象到引用,正如其他編程語言的 new 關(guān)鍵字一樣,不是嗎?

既然說到了值對(duì)象和引用對(duì)象,再說一遍老生常談的問題,函數(shù)或者說方法傳遞時(shí)應(yīng)該傳遞哪一種類型?

值傳遞還是引用傳遞

接下來的示例和動(dòng)態(tài)數(shù)組并沒有什么關(guān)系,簡(jiǎn)單起見,新開一個(gè)結(jié)構(gòu)體叫做 Employee,順便回顧一下目前學(xué)到的封裝知識(shí).

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

首先測(cè)試引用傳遞,這也是結(jié)構(gòu)體常用的傳遞方式,行為表現(xiàn)上和其他的主流編程語言表現(xiàn)一致,方法內(nèi)的修改會(huì)影響調(diào)用者的參數(shù).

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 


go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

unsafe.Pointer(&e.Name) 是查看變量的內(nèi)存地址,可以看出來調(diào)用前后的地址是同一個(gè).

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 


go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

調(diào)用者發(fā)送的內(nèi)存地址和接收者接收的內(nèi)存地址不一樣,符合期望,值傳遞都是拷貝變量進(jìn)行傳遞的嘛!

值類型還是引用類型的區(qū)分無需贅述,接下來請(qǐng)關(guān)注一個(gè)神奇的事情,方法的接收者是值類型,方法的調(diào)用者是不是一定要傳遞值類型呢?

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

方法的調(diào)用者分別傳遞值類型和引用類型,兩者均能正常工作,是不是很神奇,好像和方法的定義沒什么關(guān)系一樣!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 


go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

雖然方法的接收者要求的是值類型,調(diào)用者傳遞的是值類型還是引用類型均可!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

僅僅更改了方法接收者的類型,調(diào)用者不用做任何更改,依然可以正常運(yùn)行!

這樣就很神奇了,方法的接受者不論是值類型還是指針類型,調(diào)用者既可以是值類型也可以是指針類型,為什么?

同樣的,基于語義進(jìn)行分析,方法的設(shè)計(jì)者和調(diào)用者之間可以說是松耦合的,設(shè)計(jì)者的更改對(duì)于調(diào)用者來說沒有太大影響,這也就意味著以后設(shè)計(jì)者覺得用值類型接收參數(shù)不好,完全可以直接更改為指針類型而不用通知調(diào)用者調(diào)整邏輯!

這其實(shí)要?dú)w功于 Go 語言到設(shè)計(jì)者很好的處理了值類型和指針類型的調(diào)用方式,不論是值類型還是引用類型,一律使用點(diǎn)操作符 . 調(diào)用方法,并不像有的語言指針類型是 -> 或 * 前綴才能調(diào)用指針類型的方法.

有所為有所不為,可能正是看到了這兩種調(diào)用方式帶來的差異性,Go 全部統(tǒng)一成點(diǎn)操作符了!

雖然形式上兩種調(diào)用方式是一樣的,但是設(shè)計(jì)方法或者函數(shù)時(shí)到底應(yīng)該是值類型還是指針類型呢?

這里有三點(diǎn)建議可供參考:

  • 如果接收者需要更改調(diào)用者的值,只能使用指針類型
  • 如果參數(shù)本身非常大,拷貝參數(shù)比較占用內(nèi)存,只能用指針類型
  • 如果參數(shù)本身具有狀態(tài),拷貝參數(shù)可能會(huì)影響對(duì)象的狀態(tài),只能用指針類型
  • 如果是內(nèi)建類型或者比較小的結(jié)構(gòu)體,完全可以忽略拷貝問題,推薦用值類型.

當(dāng)然,實(shí)際情況可能還和業(yè)務(wù)相關(guān),具體用什么類型還要自行判斷,萬一選用不當(dāng)也不用擔(dān)心,更改一下參數(shù)類型就好了也不會(huì)影響調(diào)用者的代碼邏輯.

封裝后如何訪問

封裝問題基本上講解清楚了,一般來說,封裝之后的結(jié)構(gòu)體不僅是我們自己使用還有可能提供給外界使用,與此同時(shí)要保證外界不能隨意修改我們的封裝邏輯,這一部分就涉及到訪問的控制權(quán)限了.

Go 語言的訪問級(jí)別有兩種,一種是公開的另一種就是私有的,由于沒有繼承特性,也不涉及子類和父類之間訪問權(quán)限繼承問題,頓時(shí)覺得沒有繼承也不是什么壞事嘛,少了很多易錯(cuò)的概念!

雖然現(xiàn)在理解起來很簡(jiǎn)單,具體實(shí)際使用上是否便利還不好判斷.

關(guān)于可見性的命名規(guī)范如下:

  • 名稱一般使用大駝峰命名法即 CamelCase
  • 首字母大寫表示公開的 public ,小寫表示私有的 private .
  • 上述規(guī)則不僅適用于方法,包括結(jié)構(gòu)體,變量和常量等幾乎是 Go 語言的全部.

那么問題了,這里的 public 和 private 是針對(duì)誰來說?

Go 語言中的基本結(jié)構(gòu)是包 package,這里的包和目錄有區(qū)別,并不像 JAVA 語言那樣包和目錄嚴(yán)格相關(guān)聯(lián)的,這一點(diǎn)對(duì)于 Java 小伙伴來說需要特別注意.

包是相關(guān)代碼的集合,這些代碼可能存放于不同的目錄文件中,就是通過包 package 的聲明告訴 Go編譯器說:我們是一個(gè)家族整體.

如果不同的文件目錄可以聲明在同一個(gè)包中,這樣相當(dāng)于允許家族外遷,只保留姓氏就好.

還是用代碼說話吧,散落在各地的小伙伴能不能有共同的姓氏!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 


go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

pack.go 源碼文件和 pack_test 測(cè)試文件都位于相同的目錄 pack 下且包的聲明也相同都是 pack.

這種情況相當(dāng)于一家氏族位于一個(gè)村落中一起生活,和其他語言到表現(xiàn)一致.

現(xiàn)在試一下這個(gè)氏族的一部分人能不能搬到其他村落居住呢?

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

難不成跨域地域有點(diǎn)大,不支持定義方法嗎?那移動(dòng)一下使其離 pack 目錄近一點(diǎn)試試看!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

還是不行,不能新建子目錄,那么和原來在一個(gè)目錄下呢?

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

只有這樣是可以被標(biāo)識(shí)位結(jié)構(gòu)體的方法的,如果不是方法,完全可以任意存放,這一點(diǎn)就不再演示了,小伙伴可自行測(cè)試一下喲!

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

"github.com/snowdreams1006/learn-go/oop/pack" 是當(dāng)前文件中導(dǎo)入依賴包路徑,因此調(diào)用者能否正常訪問到我們封裝的結(jié)構(gòu)體.

在當(dāng)前結(jié)構(gòu)體中的屬性被我們?cè)O(shè)置成了小寫字母開頭,所以不在同一包是無法訪問該屬性的.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

封裝后如何擴(kuò)展

設(shè)計(jì)者封裝好對(duì)象供其他人使用,難免會(huì)有疏忽不足之處,此時(shí)使用者就需要擴(kuò)展已存在的結(jié)構(gòu)體了.

如果是面向?qū)ο蟮脑O(shè)計(jì)思路,最簡(jiǎn)單的實(shí)現(xiàn)方式可能就是繼承了,重寫擴(kuò)展什么的都不在話下,可是 Go 并不這么認(rèn)為,不支持繼承!

所以剩下的方法就是組合了,這也是學(xué)習(xí)面向?qū)ο髸r(shí)的前人總結(jié)的一種經(jīng)驗(yàn): 多用組合少用繼承!

現(xiàn)在想一想,Go 語言不但貫徹了這一思想,更是嚴(yán)格執(zhí)行了,因?yàn)?Go 直接取消了繼承特性.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 


go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

通過自定義結(jié)構(gòu)體內(nèi)部屬性是 Lang 類型,進(jìn)而擴(kuò)展原來 Lang 不具備的方法或者重寫原來的方法.

如果我們的自定義結(jié)構(gòu)體剛好只有這么一個(gè)屬性,完全可以使用簡(jiǎn)化形式,說到這里其實(shí)有必要特別說明一下,專業(yè)叫法稱之為別名.

go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

作為設(shè)計(jì)者和使用者都已經(jīng)考慮到了,封裝的基本知識(shí)也要告一段落了,由于 Go 不支持繼承,也沒必要演示相關(guān)代碼,唯一剩下的只有接口了.

雖然 Go 同樣是不支持多態(tài),但是 Go 提供的接口確實(shí)與眾不同,別有一番滋味在心頭,下一節(jié)將開始探索接口.

關(guān)于封裝的復(fù)盤

  • 定義結(jié)構(gòu)體字段
go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

結(jié)構(gòu)體有多個(gè)字段時(shí)彼此直接換行,不用逗號(hào)也不用分號(hào)之類的,不要多此一舉.

  • 定義結(jié)構(gòu)體方法
go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

原本是普通的函數(shù),函數(shù)名前面加入指向當(dāng)前結(jié)構(gòu)體的參數(shù)時(shí),函數(shù)不再是函數(shù)而是方法,同時(shí)當(dāng)前結(jié)構(gòu)體參數(shù)叫做接收者,類似于其他面向?qū)ο笳Z言中的 this 或 self 關(guān)鍵字實(shí)現(xiàn)的效果.

  • 字面量聲明結(jié)構(gòu)體
go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

字面量聲明結(jié)構(gòu)體除了這種類似于有參構(gòu)造函數(shù)使用方式,還有無參和全參構(gòu)造函數(shù)使用方式,這里說的構(gòu)造函數(shù)只是看起來像并不真的是構(gòu)造函數(shù).

  • new 聲明結(jié)構(gòu)體
go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

new 函數(shù)和其他主流的編程語言 new 關(guān)鍵字類似,用于聲明結(jié)構(gòu)體,不同于字面量聲明方式,new 函數(shù)的輸出對(duì)象是指針類型.

  • 首字母大小寫控制訪問權(quán)限

不論是變量名還是方法名,名稱首字母大寫表示公開的,小寫表示私有的.

  • 代碼的基本組織單元是包

訪問控制權(quán)限也是針對(duì)代碼包而言,一個(gè)目錄下只有一個(gè)代碼包,包名和目錄名沒有必然聯(lián)系.

  • 復(fù)合擴(kuò)展已有類型
go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

自定義結(jié)構(gòu)體內(nèi)嵌其他結(jié)構(gòu)體,通過復(fù)合而不是繼承的方式實(shí)現(xiàn)對(duì)已有類型的增強(qiáng)控制,也是一種推薦的編程規(guī)范.

  • 別名擴(kuò)展已有類型
go 學(xué)習(xí)筆記之詳細(xì)說一說封裝是怎么回事

 

別名可以看成單字段結(jié)構(gòu)體的簡(jiǎn)化形式,可以用來擴(kuò)展已存在的結(jié)構(gòu)體類型,也支持方法等特性.

最后,非常感謝你的閱讀,鄙人知識(shí)淺薄,如有描述不當(dāng)?shù)牡胤?還請(qǐng)各位看官指出,你的每一次留言我都會(huì)認(rèn)真回復(fù),你的轉(zhuǎn)發(fā)就是對(duì)我最大的鼓勵(lì)!

 

如果需要查看相關(guān)源碼,可以直接訪問 https://github.com/snowdreams1006/learn-go,同時(shí)也推薦關(guān)注公眾號(hào)與我交流.

分享到:
標(biāo)簽:封裝 語言
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定