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

ove*_*nge -3 struct pointers go slice

在下面的代码中:

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 

}
Run Code Online (Sandbox Code Playgroud)

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

icz*_*cza 7

如果这些类型确实相等,请使用类型别名

type PostRequestModel = ProductEntity
Run Code Online (Sandbox Code Playgroud)

如果你这样做,你可以简单地转换ProductEntityListRequestBody(在Go Playground上尝试):

func convertModelToEntity(modelList RequestBody) ProductEntityList {
    return ProductEntityList(modelList) // Works!!
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

所以*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
}
Run Code Online (Sandbox Code Playgroud)

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

func convertModelToEntity(modelList RequestBody) ProductEntityList {
    return *(*ProductEntityList)(unsafe.Pointer(&modelList))
}
Run Code Online (Sandbox Code Playgroud)

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