如何将数据从一种类型复制到具有相同结构的另一种类型?

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 

}

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

如果这些类型真的相等,使用type alias:

type PostRequestModel = ProductEntity

如果这样做,您可以简单地将 ProductEntityList 转换为 RequestBody(在 Go Playground 上尝试):

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

如果不能使用类型别名,则无法从一个切片转换为另一个切片。您必须创建一个新切片。请注意,您可以转换单个切片元素,因为指向的结构类型具有相同的字段。这是可能的,因为 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.

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

Go Playground 上试试:

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

另请注意,如果 RequestBodyProductEntityList 具有相同的内存布局(在您的示例中是相同的),您可以使用包 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))
}

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