首页 > 解决方案 > 如何将数据从一种类型复制到具有相同结构的另一种类型?

问题描述

在下面的代码中:

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 

}

如何将具有相同结构的数据从一种类型复制到另一种类型?因为RequestBodyandProductEntityList是两种不同的类型定义

标签: gopointersstructslice

解决方案


如果这些类型确实相等,请使用type alias

type PostRequestModel = ProductEntity

如果你这样做,你可以简单地从转换ProductEntityList为(在Go PlaygroundRequestBody上试试):

func convertModelToEntity(modelList RequestBody) ProductEntityList {
    return ProductEntityList(modelList) // Works!!
}

如果你不能使用类型别名,那么你就不能从一个切片转换到另一个切片。您必须创建一个新切片。请注意,您可以转换各个切片元素,因为指向的结构类型具有相同的字段。这是可能的,因为规格:转换:

在以下任何一种情况下,非常量值x都可以转换为类型:T

  • [...]
  • 忽略 struct 标记(见下文),x的类型 和T未定义类型的指针类型,它们的指针基类型具有相同的基础类型。

So*ProductEntity可以转换为*PostRequestModel(反之亦然),因为ProductEntityand的基础类型PostRequestModel是“相同”的结构类型。

在Go Playground上尝试一下:

func convertModelToEntity(modelList RequestBody) ProductEntityList {
    r := make(ProductEntityList, len(modelList))
    for i, m := range modelList {
        r[i] = (*ProductEntity)(m)
    }
    return r
}

另请注意,如果RequestBodyProductEntityList具有相同的内存布局(它们在您的示例中),您可以使用 packageunsafe来简单地转换它们,但我宁愿避免它(在Go Playground上尝试):

func convertModelToEntity(modelList RequestBody) ProductEntityList {
    return *(*ProductEntityList)(unsafe.Pointer(&modelList))
}

为什么要避免这种情况?使用包unsafe您的应用程序可能会变得不可移植,并且 Go 1 兼容性保证可能不适用于它。例如,您可以向 only 添加一个字段,ProductEntity但不能向PostRequestModel. 结果,您的应用程序将继续编译而不会出现错误,但可能随时崩溃。始终将包裹unsafe视为最后的手段。


推荐阅读