假设我有两个类似的集合,设置如下:
type type1 []struct {
Field1 string
Field2 int
}
type type2 []struct {
Field1 string
Field2 int
}
如果已知类型1和类型2具有相同的字段,除了编写一个将源中的所有字段复制到目标中的循环之外,是否有一种直接的方法将值从类型1写入类型2?
谢谢。
假设我有两个类似的集合,设置如下:
type type1 []struct {
Field1 string
Field2 int
}
type type2 []struct {
Field1 string
Field2 int
}
如果已知类型1和类型2具有相同的字段,除了编写一个将源中的所有字段复制到目标中的循环之外,是否有一种直接的方法将值从类型1写入类型2?
谢谢。
就您的具体示例而言,您可以轻松地将其转换为playground:
t1 := type1{{"A", 1}, {"B", 2}}
t2 := type2(t1)
fmt.Println(t2)
var mySlice []type1
),那么是否有任何简单的方法可以将mySlice转换为[]type2
? - sgonzalez为了参考OneOfOne的答案,请参阅规范的Conversions部分。
它指出:
非常量值
x
可以在以下任何情况下转换为类型T
:
x
可以赋值给T
。x
的类型和T
具有相同的基础类型。x
的类型和T
都是未命名指针类型,它们的指针基础类型具有相同的基础类型。x
的类型和T
都是整数或浮点数类型。x
的类型和T
都是复数类型。x
是整数或字节或符文片段,而T
是字符串类型。x
是字符串,而T
是字节或符文片段。
第一个被突出显示的情况就是你的情况。两种类型都具有相同的基础类型。
[]struct { Field1 string Field2 int }
底层类型的定义如下:
如果
T
是预声明的布尔型、数字型或字符串型之一,或者是一个类型字面量,则相应的底层类型就是T
本身。否则,T
的底层类型就是它在类型声明中所引用的类型的底层类型。(规范,Types)
您正在使用类型字面量来定义您的类型,因此这个类型字面量就是您的底层类型。
cannot convert res (type []struct { Name string "json:\"a.name\"" }) to type ListSociete
使用类型
type Societe struct {Name string}
和
type ListSociete []Societe
。我运行了一个 return ListSociete(res)
。
这是因为 json 标签 a.name
吗? - Nicolas Marshalltype t1 struct {
Field1 string
}
type t2 struct {
Field1 string `json:"field_1"`
}
更新:截至Go 1.8版本,此内容已不再适用。
具体来说,我所做的是:
type originalStruct []struct {
Field1 string
Field2 int
}
targetStruct := make(map[string]interface{}) // `targetStruct` can be anything of your choice
temporaryVariable, _ := json.Marshal(originalStruct)
err = json.Unmarshal(temporaryVariable, &targetStruct)
if err != nil {
// Catch the exception to handle it as per your need
}
看起来可能像个技巧,但在我的大多数任务中非常有用。
json: "-"
将是更清晰的实现结构体转换的方式。但是,如果您需要更多的灵活性,则使用映射作为中间状态是有帮助的,这将导致额外的行和处理成本(因为 Marshal 和 Unmarshal 是昂贵的)。请随时纠正我或添加任何其他原因。 - Furqan Rahamath对于已经支持泛型的Go v1.18来说,基本上我只需要创建一个接受任意类型参数并使用json.Marshal / Unmarshal将其转换为另一种类型的方法。
// utils.TypeConverter
func TypeConverter[R any](data any) (*R, error) {
var result R
b, err := json.Marshal(&data)
if err != nil {
return nil, err
}
err = json.Unmarshal(b, &result)
if err != nil {
return nil, err
}
return &result, err
}
// models.CreateUserRequest
type CreateUserRequest struct {
Fullname string `json:"name,omitempty"`
RegisterEmail string `json:"email,omitempty"`
}
// models.User
type User struct {
Name string `json:"name,omitempty"`
Email string `json:"email,omitempty"`
Phone string `json:"phone,omitempty"`
}
我可以像下面这样使用上述的工具方法
user := models.CreateUserRequest {
Name: "John Doe",
Email: "johndoe@gmail.com"
}
data, err := utils.TypeConverter[models.User](&user)
if err != nil {
log.Println(err.Error())
}
log.Println(reflrect.TypeOf(data)) // will output *models.User
log.Println(data)
您可以手动使用映射函数,将类型为t1的每个元素映射到类型为t2的元素。这样做是可行的。
func GetT2FromT1(ob1 *t1) *t2 {
ob2 := &t2 { Field1: t1.Field1, }
return ob2
}
Agniswar Bakshi的回答如果您可以手动编写这些转换,那么速度更快、效果更好,但是这里对Furqan Rahamath的回答进行了扩展。(更完整的示例可在Golang playground上找到)
func Recast(a, b interface{}) error {
js, err := json.Marshal(a)
if err != nil {
return err
}
return json.Unmarshal(js, b)
}
// Usage:
type User struct {
Name string
PasswordHash string
}
// remove PasswordHash before providing user:
type PrivateOutgoingUser struct {
Name string
}
u1 := &User{Name: "Alice", PasswordHash: "argon2...."}
u2 := &PrivateOutgoingUser{}
err = Recast(u1, u2)
if err != nil {
log.Panic("Error recasting u1 to u2", err)
}
log.Println("Limited user:", u2)
还有另一种方法,它使用了JSON标记,速度更快,因为它不需要额外的编组-解组步骤,但灵活性稍逊一些:
type User struct {
Name string
PasswordHash string `json:"-"` // - removes the field with JSON
}
user := &User{Name: "Tommy Tester", PasswordHash: "argon2...."}
js, err := json.Marshal(user)
log.Println("Limited user:", string(user))