參數太靈活容易出錯
(金慶的專欄 2020.7)
golang中可以將參數類型設為 interface{}, 這樣就可以傳入任意類型的參數,
和 C++ 中 void* 的作用相似。
但是這種萬能類型應該盡量少用,盡量使用具體的類型,或者使用一個具體的接口類型。
主要的原因是, 讓編譯期的類型檢查擋住編碼錯誤,減少運行期的錯誤。
例如,go-mongo-driver 有個創建索引的參數:
```
type IndexModel struct {
// A document describing which keys should be used for the index. It cannot be nil.
// This must be an order-preserving type such as bson.D. Map types such as bson.M are not valid.
Keys interface{}
...
}
```
其中 Keys 可以是任意類型,如 1234, "abcd", 當然不符合索引要求的類型會返回失敗。
但是 bson.M 類型,會創建索引成功,但是索引的次序會有錯誤。
注釋中已指出,不要用 bson.M, 應該使用 bson.D.
正確的 Keys 如下,表示復合索引 (field1, field2),1表示正序,-1則反序:
```
indexModel.Keys := bson.D{{"field1", 1}, {"field2", 1}}
```
如果使用 bson.M, 實際上是個 map:
```
indexModel.Keys := bson.M{"field1":1, "field2": 1}
```
因為 map 成員的次序不定,最后創建的索引可能是 (field1, field2),也可能是 (field2, field1)。
此處類型允許 interface{} 的想法是,允許任意類型,會 bson 編碼后傳給 mongo 服務器,并不會進行類型檢查。
這種靈活性非常容易造成錯誤,并且如何使用也不明確, 僅靠注釋作用很小。
(金慶的專欄 2020.7)
golang中可以將參數類型設為 interface{}, 這樣就可以傳入任意類型的參數,
和 C++ 中 void* 的作用相似。
但是這種萬能類型應該盡量少用,盡量使用具體的類型,或者使用一個具體的接口類型。
主要的原因是, 讓編譯期的類型檢查擋住編碼錯誤,減少運行期的錯誤。
例如,go-mongo-driver 有個創建索引的參數:
```
type IndexModel struct {
// A document describing which keys should be used for the index. It cannot be nil.
// This must be an order-preserving type such as bson.D. Map types such as bson.M are not valid.
Keys interface{}
...
}
```
其中 Keys 可以是任意類型,如 1234, "abcd", 當然不符合索引要求的類型會返回失敗。
但是 bson.M 類型,會創建索引成功,但是索引的次序會有錯誤。
注釋中已指出,不要用 bson.M, 應該使用 bson.D.
正確的 Keys 如下,表示復合索引 (field1, field2),1表示正序,-1則反序:
```
indexModel.Keys := bson.D{{"field1", 1}, {"field2", 1}}
```
如果使用 bson.M, 實際上是個 map:
```
indexModel.Keys := bson.M{"field1":1, "field2": 1}
```
因為 map 成員的次序不定,最后創建的索引可能是 (field1, field2),也可能是 (field2, field1)。
此處類型允許 interface{} 的想法是,允許任意類型,會 bson 編碼后傳給 mongo 服務器,并不會進行類型檢查。
這種靈活性非常容易造成錯誤,并且如何使用也不明確, 僅靠注釋作用很小。


