英文:
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论