go語言支援使用者自定義型別,而自定義型別中還可以再嵌入其他自定義的型別,被嵌入的型別被稱為「內嵌型別/內部型別」,而嵌入內部型別的就被成為「外部型別」。
通過嵌入型別,與內部型別相關的字段、方法、識別符號等都會被外部型別所擁有,就像外部型別自己的一樣,這樣就達到了**快捷復用組合的目的。
然而內嵌型別的存在,也讓 共享pkg包中某個型別值,但禁止對該型別值進行複製(建立新位址、重新指向),僅以共享的方式傳遞 成為可能。這句總結可以說是十分抽象。下面將防盜門的使用這一常見場景來進行示例講解:
防盜門的生產和使用場景:
廠商可以生產防盜門,交到客戶手中(安裝門)時也會把門的密碼告訴客戶
建立的防盜門初始密碼都是不相同的
客戶輸入密碼,密碼正確的話可以開啟防盜門
客戶修改密碼,輸入新舊密碼,密碼正確的話可以修改防盜門密碼為新密碼
客戶關上防盜門
在設計功能之前,需要先思考下:
防盜門的本質是什麼?門。門的話,肯定就能夠「開門」和「關門」,但是如果直接由客戶來操作門,顯然沒有任何的安全性。這裡必須由防盜門來操作門,而客戶只能夠操作防盜門,從而保證了安全。門這一本質也由防盜門包含。
對內-門 (結構:門狀態)
為防止對door型別值進行複製(建立新位址、重新指向),建立防盜門的方法提供給客戶,但方法內部初始化防盜門,便是實現「防盜門1用的門1,永遠不會被更改使用門2、門3,門1也永遠只有防盜門1使用」。
由需求上分析可知:「門」這一本質也由「防盜門」包含,那麼**實現上便可將door
門作為securitydoor
的內嵌型別。
由於防盜門的修改密碼、開門等操作,都是針對「防盜門」本身的,並不是對其複製物件做處理。所以對應操作方法的接收者都是指標接收者。同理,「門」的操作方法也都是指標接收者,且作為securitydoor
結構的內嵌型別也是傳的*door
如果防盜門是可複製的,那我知道防盜門1的密碼,再複製防盜門2,這樣所有的防盜門密碼都是一樣,那就可以被亂開了。為防止此類情況發生,防盜門的建立方法便將指標型別直接返回給客戶進行處理(也可理解為返回了乙個安裝在***地方的防盜門,相當於定義了防盜門不可複製。就算你想去複製,拿到的也是***地方的防盜門,即防盜門1本身,並不是建立了新的防盜門2,只是給防盜門1起了個別名叫做防盜門2)
**實現的目錄結構如下所示。將「防盜門」和「門」相關功能放在door_factory/door_factory.go
檔案中,並作為包。main.go
檔案為模擬客戶操作防盜門
/** 結果輸出:
輸入密碼開啟防盜門: 門已開啟
關閉防盜門: 門已關閉
更新密碼成功
輸入舊密碼開門: 密碼錯誤
*/}door_factory/door_factory.go
檔案:
package door_factory
import
("bytes"
"crypto/rand"
"fmt"
"math/big"
)type securitydoor struct
//建立乙個防盜門
func
createsecuritydoor()
(*securitydoor,
string),
password: password,
}return
&securitydoor, password
}//更改防盜門的密碼
func
(securitydoor *securitydoor)
changepassword
(oldpwd string
, newpwd string)(
string
,bool
) securitydoor.password = newpwd
return
"更新密碼成功"
,true
}//門,外部無法呼叫,僅包內可用,但外部可以獲得當前門是否開啟的狀態
type door struct
//防盜門開門方法-需要輸密碼,外部呼叫
func
(securitydoor *securitydoor)
opendoor
(password string
)string
return securitydoor.door.
opendoor()
}//door開門方法-僅包內可用
func
(door *door)
opendoor()
string
door.isopen =
true
return
"門已開啟"
}//door關門方法-外部也可呼叫
func
(door *door)
closedoor()
string
door.isopen =
false
return
"門已關閉"
}//指定位數隨機數
func
createrandomnumber
(len
int)
string
var container string
length := bytes.
newreader
(numbers)
.len()
for i :=
1; i <=
len; i++
container += fmt.
sprintf
("%d"
, numbers[random.
int64()
])}return container
}
6 5 Go語言型別內嵌和結構體內嵌
結構體可以包含乙個或多個匿名 或內嵌 字段,即這些字段沒有顯式的名字,只有欄位的型別是必須的,此時型別也就是欄位的名字。匿名字段本身可以是乙個結構體型別,即結構體可以包含內嵌結構體。可以粗略地將這個和物件導向語言中的繼承概念相比較,隨後將會看到它被用來模擬類似繼承的行為。go語言中的繼承是通過內嵌或...
Go型別轉換 實現
轉換 主要包含時間的轉換 byte型別轉換 string型別轉換 int型別轉換 uint型別轉換 float型別轉換 bool型別轉換以及inte ce型別轉換。其中conversion.go為實現檔案,conversion test.go為測試檔案測試通過可放心使用。呼叫示例可參考測試用例。im...
ES中使用nested型別的內嵌物件
put articles name 這樣articles就有了payment這個nested型別的字段,payment裡面的物件有amount和name,表示金額和姓名。產生如下資料,表示jack給文章1讚賞了29元,ross給文章1讚賞30元,ross給文章2讚賞31元。post articles...