Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 355
rcorre Avatar asked Sep 06 '17 19:09

rcorre


Video Answer


2 Answers

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

like image 159
JimB Avatar answered Oct 13 '22 15:10

JimB


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)
}


like image 1
Shmulik Klein Avatar answered Oct 13 '22 15:10

Shmulik Klein