In golang why I can't use the struct as nested struct type? - go

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

Related

Assignability question in golang specification

While reading go specification "Assignability" section, I tried to execute a couple of examples to get a better understanding of the topic, and now I can't get what am I doing wrong in my code.
According to the specification,
One of the cases when a value x is assignable to a variable of type T is as follows:
x's type V and T have identical underlying types and at least one of V or T is not a defined type.
Defined type specification states that
Type definition creates a new, distinct type with the same underlying type and operations as the given type, and binds an identifier to it.
But when I try to run following code, the build fails:
func main() {
type Defined int32
var d Defined
var i int32
d = i
}
The output is:
cannot use i (type int32) as type Defined in assignment
Meanwhile, the similar example with composite literal works fine:
func main() {
type MyMap map[string]int
var x MyMap
var y map[string]int
x = y
}
playground
Also from the spec:
https://golang.org/ref/spec#Numeric_types
To avoid portability issues all numeric types are defined types and thus distinct
Since type Defined int32 defines a new type, d and i don't have identical types; hence, the first clause x's type is identical to T from the assignability spec isn't applicable. The second clause x's type V and T have identical underlying types and at least one of V or T is not a defined type is not applicable as the types of both i and d are defined types. As the remaining clauses from the assignability spec do not apply in this situation, the assignment fails. Changing type Defined int32 to type Defined = int32 (which aliases a type) fixes the error.
x = y due to the T is an interface type and x implements T clause from the assignability spec is applicable.

Assignment between custom slice type and the underlying type

Go assignment shows error for int but not for []int slice.
working code here
package main
import (
"fmt"
)
type testType []int
func main() {
var i testType
var t []int
t = i
fmt.Println("Hello, playground", t, i)
}
However, if it is int type the compiler will surely show errors here:
cannot use i (type testType) as type int in assignment
package main
import (
"fmt"
)
type testType int
func main() {
var i testType
var t int
t = i
fmt.Println("Hello, playground", t, i)
}
Why does it error out for the custom int type and not the custom []int type?
It is defined in Go language specification for assignment types:
A value x is assignable to a variable of type T ("x is assignable to
T") if one of the following conditions applies:
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 defined 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 defined 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.
In your case []int is a slice and not named type. That's why the compiler did not complain. For more information on named types go through Go specification for types:
A type determines the set of values and operations specific to values
of that type. Types may be named or unnamed. Named types are specified
by a (possibly qualified) type name; unnamed types are specified using
a type literal, which composes a new type from existing types.

How can I return a subtype of the specified return value (in this case interface{})?

I have an interface that defines one parameter to have type func(interface{}, proto.Message) interface{} and I'm trying to pass something of type func reduceMsg(a interface{}, b proto.Message) []*PersistentData to it. This results in the following compiler error:
Cannot use reduceMsg (type func(a interface{}, b proto.Message) []*PersistentData as type func(interface{}, proto.Message) interface{}
What is the reason for this error, and how can I work around it? It seems like returning a more specific type than interface{} should be legal. Here's a simple complete example that illustrates the issue:
package main
import "fmt"
func main() {
var t func() interface{} = func() []string { return []string{} }
fmt.Println(t)
}
The type of the object is the whole function signature. If the signature don't match, then it's not the same type and can't be assigned that way.
Anything can be assigned to the empty interface, because all types satisfy the interface, but in your problem neither type is the empty interface, you just have a function that returns an empty interface.
Not because a part of the function can be assigned to another it makes it the same. The type is the whole function signature. I think it's the same logic behind not being able to assign an int to an int8. You can cast them if you want, but for go, they are separate types and you need to deal with making the necessary conversions to be able to assign them.
What you can do is change your second function signature to return an empty interface like this:
func(interface{}, proto.Message) interface{}
func reduceMsg(a interface{}, b proto.Message) interface{} {
var a []*PersistentData
// do something here
return a
}
This way the function signature is the same, so it's consider the same type and you are returning an []*PersistentData. Of course you will need to do a type assertion before using it as such because the program will treat it as an {}interface because that is the type that the function returned.
Referencing the spec,
In assignments, each value must be assignable to the type of the operand to which it is assigned, with the following special cases:
Any typed value may be assigned to the blank identifier.
If an untyped constant is assigned to a variable of interface type or the blank identifier, the constant is first converted to its default type.
If an untyped boolean value is assigned to a variable of interface type or the blank identifier, it is first converted to type bool.
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.
In general, Go doesn't allow you to implicitly convert values from one type to another, with the exception of being able to use concrete-typed objects as though they were interfaces (that they implement).
In this particular case, since your function doesn't actually return an interface{}, the compiler would have to do some extra work to wrap up the return value as an interface{} and return it; if you really want to accomplish what you're trying you can do this explicitly yourself:
type Foo struct {
X int
}
func create(x int) Foo {
return Foo{X: x}
}
func main() {
var f func(int) interface{} = func(x int) interface{} {
return create(x)
}
}
which is basically doing (explicitly) the wrapping operation that you want the runtime to do implicitly.

Go: Variable to a function, returning an interface

In Go, why can I not have a variable to a function, which returns an interface type?
Here's a minimal test case:
type DummyInterface interface {
Method(string) string
}
// Dummy implements the DummyInterface interface
type Dummy struct{}
func (d Dummy) Method(i string) string {
return i
}
// DummyFunc returns a Dummy pointer (which implements the DummyInterface interface)
var DummyFunc (func() *Dummy) = func() *Dummy {
a := Dummy{}
return &a
}
// DummyInterfaceFunc is declared as returning function returning an object which implements DummyInterface -- it
// is set to DummyFunc, which does return a conforming object
var DummyInterfaceFunc (func() DummyInterface) = DummyFunc
This fails to compile (Playground example here), stating:
cannot use DummyFunc (type func() *Dummy) as type func() DummyInterface in assignment
Yet, as you can see, a *Dummy does implement DummyInterface.
Why is this?
Because *Dummy is not the same type as DummyInterface. The rule that you can assign an object to something of an interface type that object implements only applies in that literal case. If the interface type appears in one of the parameters of a type (i.e. the return type of a function), assignment is not possible.
Refer to the assignability rules for more information.
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.
This is a similar concept to: Can I convert a []T to an []interface{}?
Basically func() *Dummy is a different type from func() DummyInterface, and conversion between them is not possible.
You will need to use the interface throughout to make the function signature the same.

What is the difference between type conversion and type assertion?

What is the main differences between :
v = t.(aType) // type assertion
v = aType(t) // type conversion
Where should I use type assertion or type conversion ?
A type assertion asserts that t (an interface type) actually is a aType and t will be an aType; namely the one wrapped in the t interface. E.g. if you know that your var reader io.Reader actually is a *bytes.Buffer you can do var br *bytes.Buffer = reader.(*bytes.Buffer).
A type conversion converts one (non-interface) type to another, e.g. a var x uint8 to and int64 like var id int64 = int64(x).
Rule of thumb: If you have to wrap your concrete type into an interface and want your concrete type back, use a type assertion (or type switch). If you need to convert one concrete type to an other, use a type conversion.
tl;dr x.(T) asserts that the dynamic value of interface x is T at run time; T(x) converts the type of an expression x to some other type.
Type Assertion
You know that in Go an interface is basically a method set specification, and you can assign to an interface variable any value whose type implements that method set1.
The type assertion written x.(T) asserts that the value stored in the interface x is of type T. You use a type assertion when you want to unbox that value.
One of the most common uses is when you have interface{} and you need to retrieve the concrete value it stores. A typical example, Context values:
func foo(ctx context.Context) {
s := ctx.Value("my_key").(string) // signature is `Value(key interface{}) interface{}`
// do something with s...
}
It is called assertion because at compile time it is not known whether x actually holds the concrete type T, but you assert that it does. That's why the unchecked assertion y := x.(T) panics if x doesn't actually hold a T — you must use the comma-ok assignment v, ok := x.(T) to avoid it.
ctx = context.WithValue(ctx, "my_key", "foo")
s := ctx.Value("my_key").(int) // panic
v, ok := ctx.Value("my_key").(string)
fmt.Println(v, ok) // "foo" true
In addition, when T in x.(T) is an interface itself, the assertion checks that the value stored in x implements T. The outcome is the same as above.
Type Conversion
A type conversion written as T(x) instead "changes the type of an expression to the type specified by the conversion", i.e. changes the type of x to T. An important property of conversions is that they are statically checked2. An invalid conversion simply won't compile:
type Foo string
type Bar int
a := "foo"
fmt.Println(Bar(a)) // cannot convert a (type string) to type Bar
The main condition for a conversion to be valid is assignability between the types involved, but there's several more, including conversions between numerical types, strings and byte/rune slices, directed channels, slices and array pointers, etc.
In simple terms, you use a conversion when you already know what are the types involved, and simply want to change one to the other:
b := []byte("foo") // converts string literal to byte slice
Notes:
1: more formally, when the value's method set is a superset of the interface method set; this is also why the empty interface interface{} can hold any value, because any set is a superset of an empty set.
2: type assertions are also checked at compile time when the type T in x.(T) does not implement the interface. In practice, this won't help you catch errors when x is interface{} since all types implement it.

Resources