英文:
How to copy data from one type to another that has identical structures?
问题
在下面的代码中:
type ProductEntity struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Price float32 `json:"price"`
SKU string `json:"sku"`
CreatedOn string `json:"-"`
UpdatedOn string `json:"-"`
DeletedOn string `json:"-"`
}
type ProductEntityList []*ProductEntity
type PostRequestModel struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Price float32 `json:"price"`
SKU string `json:"sku"`
CreatedOn string `json:"-"`
UpdatedOn string `json:"-"`
DeletedOn string `json:"-"`
}
type RequestBody []*PostRequestModel
func convertModelToEntity(modelList RequestBody) ProductEntityList {
// return entity.ProductEntityList(modelList) // type conversion error
}
如何将具有相同结构的数据从一个类型复制到另一个类型?因为RequestBody
和ProductEntityList
是两个不同的类型定义。
英文:
In the below code:
type ProductEntity struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Price float32 `json:"price"`
SKU string `json:"sku"`
CreatedOn string `json:"-"`
UpdatedOn string `json:"-"`
DeletedOn string `json:"-"`
}
type ProductEntityList []*ProductEntity
type PostRequestModel struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Price float32 `json:"price"`
SKU string `json:"sku"`
CreatedOn string `json:"-"`
UpdatedOn string `json:"-"`
DeletedOn string `json:"-"`
}
type RequestBody []*PostRequestModel
func convertModelToEntity(modelList RequestBody) ProductEntityList {
// return entity.ProductEntityList(modelList) // type conversion error
}
How to copy data from one type to another, that has identical structures? Because RequestBody
and ProductEntityList
are two different type definitions
答案1
得分: 7
如果这些类型确实相等,可以使用type alias:
type PostRequestModel = ProductEntity
如果这样做,你可以简单地将ProductEntityList
转换为RequestBody
(在Go Playground上尝试):
func convertModelToEntity(modelList RequestBody) ProductEntityList {
return ProductEntityList(modelList) // Works!!
}
如果你不能使用类型别名,那么就无法将一个切片转换为另一个切片。你必须创建一个新的切片。请注意,你可以转换单个切片元素,因为指向的结构体类型具有相同的字段。这是可能的,因为规范:转换:
非常量值
x
可以在以下任何情况下转换为类型T
:
- [...]
- 忽略结构体标签(见下文),
x
的类型和T
都是指针类型,它们不是定义类型,并且它们的指针基础类型具有相同的底层类型。
因此,*ProductEntity
可以转换为*PostRequestModel
(反之亦然),因为ProductEntity
和PostRequestModel
的底层类型是“相同的”结构体类型。
在Go Playground上尝试:
func convertModelToEntity(modelList RequestBody) ProductEntityList {
r := make(ProductEntityList, len(modelList))
for i, m := range modelList {
r[i] = (*ProductEntity)(m)
}
return r
}
还要注意,如果RequestBody
和ProductEntityList
具有相同的内存布局(在你的示例中是这样的),你可以使用unsafe
包来简单地转换它们,但我更愿意避免这样做(在Go Playground上尝试):
func convertModelToEntity(modelList RequestBody) ProductEntityList {
return *(*ProductEntityList)(unsafe.Pointer(&modelList))
}
为什么要避免这样做?使用unsafe
包可能会使你的应用程序不可移植,并且Go 1的兼容性保证可能不适用于它。例如,你可能只向ProductEntity
添加一个字段,而不是PostRequestModel
。结果,你的应用程序将继续编译而没有错误,但可能随时崩溃。始终将unsafe
包视为最后的手段。
英文:
If those type are truly equal, use type alias:
type PostRequestModel = ProductEntity
If you do so, you can simply convert from ProductEntityList
to RequestBody
(try it on the Go Playground):
func convertModelToEntity(modelList RequestBody) ProductEntityList {
return ProductEntityList(modelList) // Works!!
}
If you can't use type alias, then you can't convert from one slice to another. You have to create a new slice. Note that you can convert the individual slice elements because the pointed struct types have identical fields. This is possible because Spec: Conversions:
> A non-constant value x
can be converted to type T
in any of these cases:
> - [...]
> - ignoring struct tags (see below), x
's type and T
are pointer types that are not defined types, and their pointer base types have identical underlying types.
So *ProductEntity
is convertible to *PostRequestModel
(and vice versa) because the underlying type of ProductEntity
and PostRequestModel
is the "same" struct type.
Try it on the Go Playground:
func convertModelToEntity(modelList RequestBody) ProductEntityList {
r := make(ProductEntityList, len(modelList))
for i, m := range modelList {
r[i] = (*ProductEntity)(m)
}
return r
}
Also note that if RequestBody
and ProductEntityList
have identical memory layout (they do in your example), you may use package unsafe
to simply convert them, but I'd rather avoid it (try it on the Go Playground):
func convertModelToEntity(modelList RequestBody) ProductEntityList {
return *(*ProductEntityList)(unsafe.Pointer(&modelList))
}
Why to avoid this? Using package unsafe
your app may become non-portable and the Go 1 compatibility guarantees may not apply to it. E.g. you may add a field to ProductEntity
only but not to PostRequestModel
. As a result, your app will continue to compile without errors, but may blow up at any time. Always look at package unsafe
as the last resort.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论