Golang:结构体切片之间的类型转换

huangapple go评论69阅读模式
英文:

Golang : type conversion between slices of structs

问题

这个问题是在我之前的一个问题之后提出的。

我不太明白我在下面的测试代码中将res转换为ListSociete时出了什么问题:

import (
	"errors"
	"fmt"
	"github.com/jmcvetta/neoism"
)

type Societe struct {
	Name string
}

type ListSociete []Societe

func loadListSociete(name string) (ListSociete, error) {
	db, err := neoism.Connect("http://localhost:7474/db/data")
	if err != nil {
		return nil, err
	}
	res := []struct {
		Name string `json:"a.name"`
	}{}
	cq := neoism.CypherQuery{
		Statement: `
			MATCH (a:Societe)
			WHERE a.name = {name}
			RETURN a.name
			`,
		Parameters: neoism.Props{"name": name},
		Result:     &res,
	}
	db.Cypher(&cq)
	if len(res) == 0 {
		return nil, errors.New("Page does not exist")
	}
	r := res[0]
	return ListSociete(res), nil
}

[]struct{Name string}[]struct{Name string json:"a.name" }是不同的吗?

或者ListSociete[]struct{Name string}是不同的吗?

谢谢。

英文:

This questions follows another question of mine.

I don't exactly get what is wrong with my attempt to convert res to a ListSociete in the following test code :

import (
	"errors"
	"fmt"
	"github.com/jmcvetta/neoism"
)

type Societe struct {
	Name string
}

type ListSociete []Societe

func loadListSociete(name string) (ListSociete, error) {
	db, err := neoism.Connect("http://localhost:7474/db/data")
	if err != nil {
		return nil, err
	}
	res := []struct {
		Name string `json:"a.name"`
	}{}
	cq := neoism.CypherQuery{
		Statement: `
			MATCH (a:Societe)
			WHERE a.name = {name}
			RETURN a.name
			`,
		Parameters: neoism.Props{"name": name},
		Result:     &res,
	}
	db.Cypher(&cq)
	if len(res) == 0 {
		return nil, errors.New("Page duz not exists")
	}
	r := res[0]
	return ListSociete(res), nil
}

Is a []struct{Name string} different from a []struct{Name string json:"a.name" } ?

Or is a ListSociete different from a []struct{Name string} ?

Thanks.

答案1

得分: 11

你目前正在处理两种不同的类型:

type Societe struct {
    Name string
}

和匿名类型:

struct {
    Name string `json:"a.name"`
}

如果没有标签,这两个类型将是相同的。**Go规范**指出(我强调):
> 如果两个结构类型具有相同的字段顺序,并且相应的字段具有相同的名称、相同的类型和相同的标签,则它们是相同的。
> 两个匿名字段被认为具有相同的名称。来自不同包的小写字段名称始终是不同的。

因此,你不能简单地在两者之间进行转换。而且,你将两种类型的切片进行转换会使转换变得复杂。我可以看到你有两个选择:

通过迭代进行复制:

这是安全且推荐的解决方案,但它也更冗长和慢。

ls := make(ListSociete, len(res))
for i := 0; i < len(res); i++ {	
	ls[i].Name = res[i].Name
}
return ls, nil

不安全的转换:

由于这两种类型具有相同的底层数据结构,可以进行不安全的转换。
但是,这可能会在以后导致问题。请注意!

return *(*ListSociete)(unsafe.Pointer(&res)), nil

Playground示例: http://play.golang.org/p/lfk7qBp2Gb

英文:

You are currently dealing with two different types:

type Societe struct {
    Name string
}

and the anonymous one:

struct {
    Name string `json:&quot;a.name&quot;`
}

These two would be identical if it wasn't for the tag. The Go Specifications states (my emphasis):
> Two struct types are identical if they have the same sequence of fields, and if
> corresponding fields have the same names, and identical types, and identical tags.
> Two anonymous fields are considered to have the same name. Lower-case field names
> from different packages are always different.

So, you can't do a simple conversion between the two. Also, the fact that you are converting slices of the two types makes the conversion problematic. I can see two options for you:

Copy through iteration:

This is the safe and recommended solution, but it is also more verbose and slow.

ls := make(ListSociete, len(res))
for i := 0; i &lt; len(res); i++ {	
	ls[i].Name = res[i].Name
}
return ls, nil

Unsafe conversion:

Since both types have the same underlying data structure, it is possible to do an unsafe conversion.
This might however blow up in your face later on. Be warned!

return *(*ListSociete)(unsafe.Pointer(&amp;res)), nil

Playground Example: http://play.golang.org/p/lfk7qBp2Gb

答案2

得分: 1

经过一些测试,我发现以下内容:

一个被定义为ListSociete的类型...

type Societe struct {
    Name string `json:"a.name"`
}

type ListSociete []Societe

与以下内容不同:

type ListSociete []struct {
    Name string `json:"a.name"`
}

第二种解决方案有效,而第一种则无效。

所以我认为,在不编写显式循环的情况下,确实没有办法直接转换具有不同标签的类型吗?

在这种情况下,我肯定会使用循环,因为直接在类型中使用标签(参见上面的第二种解决方案)会使我的代码难以阅读和重用,而且我真的不知道使用不安全的转换方法会有什么问题。所以感谢您确认不同的标签会产生不同的类型。

英文:

So, after some tests, here's whats i found out :

A ListSociete defined as such...

type Societe struct {
    Name string `json:&quot;a.name&quot;`
}

type ListSociete []Societe

is different from this :

type ListSociete []struct {
    Name string `json:&quot;a.name&quot;`
}

This second solution works, whereas the first doesn't.

So I assume there really is no way to convert (directly without writing an explicit loop) between types with different tags ?

In that case, i'll definitely go with the loop, as using tags directly in types (cf. second solution above) would make my code unreadable and unreusable, also I really have no clue what I would be messing with using the unsafe conversion method. So thanks for confirming different tags made different types.

huangapple
  • 本文由 发表于 2014年7月9日 05:53:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/24642148.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定