Go使用內嵌型別實現額外保護 以防盜門示例

2021-10-19 08:33:30 字數 3174 閱讀 8496

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...