英文:
Setting variable type at run-time in Go
问题
我有以下的Go函数,它使用了Gorm的First()方法:
func (r *SqlRepository) Get(id int, inventory any) (any, error) {
result := db.First(&inventory, id)
if result.Error != nil {
var s struct{}
return s, result.Error
} else {
return inventory, nil
}
}
当调用Get函数并传入一个整数和我创建的一个结构体(Get(1, model.InventoryToys{}))时,我得到以下错误:
panic: reflect: reflect.Value.Set using unaddressable value
根据我的理解,any表示该值可以是任何类型,所以当我传入model.InventoryToys{}时,它应该成为inventory的类型。在Go中是不是不是这样工作的?我有什么遗漏吗?
为了提供背景,我之所以希望它是any类型,是因为我有多个用于库存的表格和多个结构体作为结果,我不想为每个结构体创建一个单独的获取函数,以避免代码重复。因此,我试图动态地将inventory的类型分配为传入的任何类型,并让Gorm去获取指定表格的数据。
英文:
I have the following Go function which uses Gorm's First():
func (r *SqlRepository) Get(id int, inventory any) (any, error) {
result := db.First(&inventory, id)
if result.Error != nil {
var s struct{}
return s, result.Error
} else {
return inventory, nil
}
}
When calling that Get and passing an int and a struct created by me (Get(1, model.InventoryToys{})) I am getting
panic: reflect: reflect.Value.Set using unaddressable value
From my understanding any means that that value can be anything so when I pass model.InventoryToys{} that should become the type of inventory. Is that not how it works in Go? Am I missing something?
Just for context the reason I want it to be any is because I have multiple tables for inventory and multiple structs as a result and I didn't want to create a separate get function for each one of them to avoid code repetition. So essentially I am trying to dynamically assign the type of inventory to whatever is passed and let Gorm go and get data from the specified table.
答案1
得分: 2
any是一个没有指定方法的接口,因此所有的数据类型都可以用any来表示。
Go是一种静态类型语言,所以你不能在运行时设置变量的类型。inventory的类型是any。inventory可以包含不同类型的不同值。在你的情况下,inventory包含了一个类型为model.InventoryToys的值。这不是一个可写的类型,它的地址不能被获取,因为它是一个值的副本。
如果你使用*model.InventoryToys,那么它就变成了可写的,因为inventory现在包含了一个指向结构体的指针,可以对它进行写操作。
所以,你必须将inventory设置为&model.InventoryToys,并将inventory传递给db.First,而不是&inventory。
英文:
any is an interface that specified no methods, so all data types can be represented by any.
Go is a statically typed language, so you cannot set the type of a variable at runtime. The type of inventory is any. inventory can contain different values of different types. In your case, inventory contains a value of type model.InventoryToys. This is not a writable type, its address cannot be taken, because it is the copy of a value.
If you use *model.InventoryToys, then it becomes writable, because inventory now contains a pointer to a struct, and it can be written.
So, you have to set inventory to &model.InventoryToys, and pass inventory into db.First, and not &inventory.
答案2
得分: 0
你可以按照下面的方式修改Get函数。
func (r *SqlRepository) Get(id int, inventory interface{}) (interface{}, error) {
result := db.First(inventory, id)
if result.Error != nil {
var s struct{}
return s, result.Error
} else {
return inventory, nil
}
}
你需要将可设置的值解析为db.First函数的指针。它应该是一个模型的指针,而不是一个接口的指针。在gorm中,他们使用了反射。请参考反射定律获取更多信息。
你可以按照下面的方式调用Get函数。
repo := SqlRepository{}
id := 1
toys := &model.InventoryToys{}
repo.Get(id, &toys)
英文:
You can modify the Get function as shown below.
func (r *SqlRepository) Get(id int, inventory any) (any, error) {
result := db.First(inventory, id)
if result.Error != nil {
var s struct{}
return s, result.Error
} else {
return inventory, nil
}
}
You need to parse settable value to the db.First function. It should be a pointer of a model & shouldn't be a pointer of an interface. In side gorm, they use reflection. Refer Laws of reflection for more information.
You can call Get function as shown below.
repo := SqlRepository{}
id := 1
toys := &model.InventoryToys{}
repo.Get(id, &toys)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论