英文:
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:"a.name"`
}
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 < 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(&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:"a.name"`
}
type ListSociete []Societe
is different from this :
type ListSociete []struct {
Name string `json:"a.name"`
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论