在golang中,为什么不能将结构用作嵌套结构类型?

The following code (play):

func main() {
    buf := bytes.NewBuffer(make([]byte, 0))
    rw := bufio.NewReadWriter(bufio.NewReader(buf), bufio.NewWriter(buf))
    var r *bufio.Writer
    r = rw
}

Gives the following compile-time error:

cannot use rw (type *bufio.ReadWriter) as type *bufio.Writer in assignment

What I expected is use a struct as a nested struct type. But if I declare r as io.Reader, this will be ok, so should I move to interface?

bufio.NewReadWriter() returns a concrete type, a pointer to a struct and bufio.Writer is also a concrete type, a struct. Neither *ReadWriter and *bufio.Writer is an interface!

In Go there is no automatic type conversion, you cannot assign a value of different concrete type to a variable.

You have 2 options:

  1. Since bufio.ReadWriter embeds *bufio.Writer, you can simply refer to it and use that in the assignment:

    var r *bufio.Writer
    r = rw.Writer
    
  2. Or you can declare r to be an io.Writer (it is an interface type) so that you can assign rw to it because rw implements io.Writer:

    var r io.Writer
    r = rw
    

    Although I don't think creating r in this case is particularly useful because whenever you would use r you could also use rw.

Check out Go spec: Assignability:

A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:

  • x's type is identical to T.
  • x's type V and T have identical underlying types and at least one of V or T is not a named type.
  • T is an interface type and x implements T.
  • x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a named type.
  • x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
  • x is an untyped constant representable by a value of type T.

None of the cases apply to your code, so it is an invalid assignment.

When r is declared to be io.Writer, it is the the following case and therefore it is valid:

T is an interface type and x implements T.

Different type can't assign, GO do not support extension.