为什么无法将结构体转换为嵌入类型?

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

Why can't a struct be converted to an embedded type

问题

package main

type Inner struct {
    x int
}

type Outer struct {
    Inner
}

func main() {
    x := Inner{1}
    y := (Outer)(x) // 无法将类型为 Inner 的 x 转换为类型 Outer
}

Go 语言规范中的 转换 部分指出:

> 非常量值 x 可以在以下任何情况下转换为类型 T:
> ...
> 忽略结构体标签(见下文),x 的类型和 T 具有相同的基础类型。
> ...

类型标识 部分则说:

> 如果两个结构体类型具有相同的字段序列,并且相应的字段具有相同的名称、相同的类型和相同的标签,则它们是相同的。

据我理解,InnerOuter 都有一个名为 x 的字段,类型为 int。那么为什么我不能将 Outer 转换为 Inner 呢?

我最终弄清楚了可以使用 x.Inner,但这花费了我一些时间,所以我很好奇为什么(在我看来)更明显的方法是不允许的。

英文:
package main

type Inner struct {
    x int
}

type Outer struct {
    Inner
}

func main() {
    x := Inner{1}
    y := (Outer)(x) // cannot convert x (type Inner) to type Outer
}

The go spec section on conversions claims that

> 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 have identical underlying types.
> ...

The section on type identity says:

> 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.

It is my understanding that both Inner and Outer have a single field x which is an int. So why can't I convert an Outer to an Inner?

I eventually figured out that I can use x.Inner, but it took me a while, so I'm curious why the (in my opinion) more obvious approach is disallowed.

答案1

得分: 8

Outer没有字段x。它有一个字段InnerInner有一个字段x。当访问.x时,选择器(.)会自动从最浅的深度提升嵌入字段,直到找到x为止。

请参阅Selectors的规范。

英文:

Outer does not have a field x. It has a field Inner, which has a field x. When accessing .x, the selector (.) will automatically promote an embedded field from the shallowest depth where there is such an x.

See the spec on Selectors

答案2

得分: 1

以下代码片段用于支持JimB的答案 - InnerOuter不共享相同的字段序列,因此不符合转换条件。

它将帮助您直观地看到InnerOuter类型之间的区别:

package main

import "fmt"

type inner struct {
	x int
}

type outer struct {
	inner
}

func main() {
	in := inner{x: 1}
	fmt.Printf("inner: %+v\n", in)
	fmt.Println()
	out := outer{in}
	fmt.Printf("outer: %+v\n", out)
}
英文:

The following code snippet is used to support JimB's answer - Inner and Outer doesn't share the same sequence of fields and therefore aren't eligible for conversion.

It will help you to literally see the difference between the Inner and Outer types:

package main

import "fmt"

type inner struct {
	x int
}

type outer struct {
	inner
}

func main() {
	in := inner{x: 1}
	fmt.Printf("inner: %+v\n", in)
	fmt.Println()
	out := outer{in}
	fmt.Printf("outer: %+v\n", out)
}


huangapple
  • 本文由 发表于 2017年9月7日 03:10:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/46082687.html
匿名

发表评论

匿名网友

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

确定