亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

防止在結構初始化中丟失字段

防止在結構初始化中丟失字段

Go
手掌心 2023-06-05 17:20:39
考慮這個例子。假設我有一個在我的代碼庫中無處不在的對象:type Person struct {    Name string    Age  int    [some other fields]}在代碼庫深處的某個地方,我還有一些創建新Person結構的代碼。也許它類似于下面的實用函數(請注意,這只是一些創建函數的示例Person——我的問題的重點不是專門詢問復制函數):func copyPerson(origPerson Person) *Person {    copy := Person{        Name: origPerson.Name,        Age:  origPerson.Age,        [some other fields]    }    return &copy}另一位開發人員出現并向結構添加了一個新Gender字段Person。但是,因為該copyPerson函數位于一段遙遠的代碼中,所以他們忘記更新copyPerson. 如果您在創建結構時省略參數,golang 不會拋出任何警告或錯誤,代碼將編譯并看起來工作正常;唯一的區別是該copyPerson方法現在無法復制Gender結構,并且結果copyPerson將Gender替換為 nil 值(例如空字符串)。防止這種情況發生的最佳方法是什么?有沒有辦法讓 golang 在特定的結構初始化中強制執行不丟失參數?是否有可以檢測此類潛在錯誤的 linter?
查看完整描述

5 回答

?
慕田峪4524236

TA貢獻1875條經驗 獲得超5個贊

我解決這個問題的方法是只使用NewPerson(params)而不是導出這個人。這使得獲取person實例的唯一方法是通過您的New方法。


package person


// Struct is not exported

type person struct {

    Name string

    Age  int

    Gender bool

}


// We are forced to call the constructor to get an instance of person

func New(name string, age int, gender bool) person {

    return person{name, age, gender}

}

這迫使每個人都從同一個地方獲得一個實例。當您添加一個字段時,您可以將它添加到函數定義中,然后在它們構造新實例的任何地方都會出現編譯時錯誤,因此您可以輕松找到它們并修復它們。


查看完整回答
反對 回復 2023-06-05
?
SMILET

TA貢獻1796條經驗 獲得超4個贊

首先,您的copyPerson()函數名不副實。它復制a 的一些字段Person,但不是(必須)全部。它應該被命名為copySomeFieldsOfPerson().


要復制完整的結構值,只需分配結構值。如果你有一個接收非指針的函數Person,那已經是一個副本,所以只需返回它的地址:


func copyPerson(p Person) *Person {

    return &p

}

就是這樣,這將復制所有現在和未來的領域Person。


現在可能存在字段是指針或類似標題的值(如切片)的情況,應該從原始字段(更準確地說是從指向的對象)“分離”,在這種情況下,您確實需要進行手動調整,例如


type Person struct {

    Name string

    Age  int

    Data []byte

}


func copyPerson(p Person) *Person {

    p2 := p

    p2.Data = append(p2.Data, p.Data...)

    return &p2

}

或者不制作另一個副本p但仍然分離的替代解決方案Person.Data:


func copyPerson(p Person) *Person {

    var data []byte

    p.Data = append(data, p.Data...)

    return &p

}

當然,如果有人添加了一個也需要手動處理的字段,這將無濟于事。


您還可以使用未加密的文字,如下所示:


func copyPerson(p Person) *Person {

    return &Person{

        p.Name,

        p.Age,

    }

}

如果有人向 中添加新字段,這將導致編譯時錯誤Person,因為未鍵控的復合結構文字必須列出所有字段。同樣,如果有人更改了可將新字段分配給舊字段的字段(例如,有人交換了具有相同類型的彼此相鄰的 2 個字段),這將無濟于事,而且不鼓勵使用未加密的文字。


包所有者最好在Person類型定義旁邊提供一個復制構造函數。因此,如果有人發生變化Person,他/她應該負責保持CopyPerson()運營。正如其他人提到的,你應該已經有了單元測試,如果CopyPerson()不符合它的名字,它應該會失敗。


最佳可行方案?

如果您不能將CopyPerson()next 放在類型旁邊Person并讓其作者維護它,請繼續進行結構值復制和手動處理指針和類似標頭的字段。


您可以創建一個person2類型,它是該Person類型的“快照”。如果原始類型發生變化,使用空白全局變量接收編譯時警報Person,在這種情況下,copyPerson()包含 的源文件將拒絕編譯,因此您將知道它需要調整。


這是可以做到的:


type person2 struct {

    Name string

    Age  int

}


var _ = Person(person2{})

Person如果和的字段person2不匹配,則空白變量聲明將不會編譯。


上述編譯時檢查的一種變體可能是使用類型化nil指針:


var _ = (*Person)((*person2)(nil))


查看完整回答
反對 回復 2023-06-05
?
慕妹3242003

TA貢獻1824條經驗 獲得超6個贊

慣用的方法是根本不這樣做,而是使零值有用。復制函數的例子并沒有真正意義,因為它完全沒有必要——你可以說:

copy?:=?new(Person)
*copy?=?*origPerson

不需要專門的功能,也不必保持字段列表是最新的。如果你想要一個新實例的構造函數NewPerson,就像理所當然的那樣,只需編寫一個并使用它。Linters 在某些方面非常有用,但沒有什么能比得上廣為人知的最佳實踐和同行代碼審查。


查看完整回答
反對 回復 2023-06-05
?
素胚勾勒不出你

TA貢獻1827條經驗 獲得超9個贊

我不知道強制執行該規則的語言規則。


也就是說,我會重新考慮這里的設計。如果Personstruct 在您的代碼庫中如此重要,請集中創建和復制它,以便“遙遠的地方”不只是創建和移動Persons。重構您的代碼,以便僅使用一個構造函數來構建Persons(可能類似于person.New返回 a?person.Person),然后您將能夠集中控制其字段的初始化方式。


查看完整回答
反對 回復 2023-06-05
?
一只斗牛犬

TA貢獻1784條經驗 獲得超2個贊

我能想出的最好的解決方案(而且不是很好)是定義一個與tempPerson該結構相同的新結構Person,并將其放在任何初始化新 Person 結構的代碼附近,并更改初始化一個Person以便它改為將其初始化為 atempPerson但隨后將其轉換為 a Person。像這樣:


type tempPerson struct {

    Name string

    Age  int

    [some other fields]

}


func copyPerson(origPerson Person) *Person {

    tempCopy := tempPerson{

        Name: orig.Name,

        Age:  orig.Age,

        [some other fields]

    }

    copy := (Person)(tempCopy)

    return &copy

}

這樣,如果將另一個字段Gender添加到Person但不添加到tempPerson代碼中,將在編譯時失敗。據推測,開發人員然后會看到錯誤,編輯tempPerson以匹配他們對 的更改Person,并在這樣做時注意到附近的代碼使用tempPerson并認識到他們應該編輯該代碼以也處理該Gender字段。


我不喜歡這個解決方案,因為它涉及在我們初始化結構Person并希望獲得這種安全性的任何地方復制和粘貼結構定義。有沒有更好的辦法?


查看完整回答
反對 回復 2023-06-05
  • 5 回答
  • 0 關注
  • 203 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號