options: | type assertions to | interface value method receiver | interface value type | result for interface type | result for interface type |
---|---|---|---|---|---|
case | x.( T) |
type / pointer | value / pointer | var x interface{} |
var x InterfaceType |
A | concrete type | type | value | true | true |
B | pointer to concrete type | type | value | false | false |
C | interface type | type | value | true | true |
D | concrete type | type | pointer | false | false |
E | pointer to concrete type | type | pointer | true | true |
F | interface type | type | pointer | true | true |
G | concrete type | pointer | value | true | static check failure |
H | pointer to concrete type | pointer | value | false | static check failure |
I | interface type | pointer | value | false | static check failure |
J | concrete type | pointer | pointer | false | static check failure |
K | pointer to concrete type | pointer | pointer | true | true |
L | interface type | pointer | pointer | true | true |
Last active
March 18, 2020 19:51
-
-
Save mtilson/4536e69d8d667823d58c78d9687e8b09 to your computer and use it in GitHub Desktop.
how type assertions rules are applied [golang]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://play.golang.org/p/SMdNNFLp3OJ | |
// See https://golang.org/ref/spec#Type_assertions for the notation of type assertion `x.(T)` and `x.(*T)`. | |
// Here we use: | |
// for `T`, `*T`: | |
// - `ConcreteTypeTypeReceiver` if T is concrete type (not an interface type) with Type Method Receiver | |
// - `ConcreteTypeTypeReceiver` satisfies `InterfaceType` interface | |
// - `*ConcreteTypeTypeReceiver` if *T is concrete type (not an interface type) with Type Method Receiver | |
// - `*ConcreteTypeTypeReceiver` satisfies `InterfaceType` interface | |
// - `*ConcreteTypePtrReceiver` if *T is concrete type (not an interface type) with Pointer Method Receiver | |
// - `*ConcreteTypePtrReceiver` satisfies `InterfaceType` interface | |
// - `InterfaceType` if T is interface type | |
// for `x`: | |
// - `InterfaceType` - defined interface type we use as interface value for type assertions | |
// - `interface{}` - empty interface we use as interface value for type assertions | |
package main | |
import "fmt" | |
type ConcreteTypeTypeReceiver struct {n int} | |
func (c ConcreteTypeTypeReceiver) someMethod() int {return c.n} | |
// declaration above SUPPORTs the following types | |
// 1. `ConcreteTypeTypeReceiver` - with methods (according to case C2) | |
// 1. `someMethod() int` | |
// 2. `*ConcreteTypeTypeReceiver` - with methods (according to case F2) | |
// 1. `someMethod() int` | |
type ConcreteTypePtrReceiver struct {n int} | |
func (c *ConcreteTypePtrReceiver) someMethod() int {return c.n} | |
// declaration above DOS NOT SUPPORT the following types | |
// 1. `ConcreteTypePtrReceiver` - with methods (according to case I2) | |
// 1. `someMethod() int` | |
// declaration above SUPPORTs the following types | |
// 1. `*ConcreteTypePtrReceiver` - with methods (according to case L2) | |
// 1. `someMethod() int` | |
type InterfaceType interface { | |
someMethod() int | |
} | |
func main() { | |
var okX, okY bool | |
fmt.Printf("options: | type assertions to | interface value method receiver | interface value type | result for interface type | result for interface type \n") | |
fmt.Printf("---- | ---- | ---- | ---- | ---- | ---- \n") | |
fmt.Printf("case | `x.(`**T**`)` | type / pointer | value / pointer | `var x interface{}` | `var x InterfaceType` \n") | |
{ | |
var x interface{} = ConcreteTypeTypeReceiver{1} | |
var y InterfaceType = ConcreteTypeTypeReceiver{1} | |
_, okX = x.(ConcreteTypeTypeReceiver) | |
_, okY = y.(ConcreteTypeTypeReceiver) | |
fmt.Printf("A | concrete type | type | value | %t | %t\n", okX, okY) // true / true | |
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;` | |
// `dynamic type of x`: ConcreteTypeTypeReceiver | |
// `type T`: ConcreteTypeTypeReceiver | |
// type ConcreteTypeTypeReceiver is identical to type ConcreteTypeTypeReceiver: result=true | |
} | |
{ | |
var x interface{} = ConcreteTypeTypeReceiver{1} | |
var y InterfaceType = ConcreteTypeTypeReceiver{1} | |
_, okX = x.(*ConcreteTypeTypeReceiver) // panic: interface conversion: interface {} is main.ConcreteTypeTypeReceiver, not *main.ConcreteTypeTypeReceiver | |
_, okY = y.(*ConcreteTypeTypeReceiver) // panic: interface conversion: main.InterfaceType is main.ConcreteTypeTypeReceiver, not *main.ConcreteTypeTypeReceiver | |
fmt.Printf("B | pointer to concrete type | type | value | %t | %t\n", okX, okY) // false / false | |
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;` | |
// `dynamic type of x`: ConcreteTypeTypeReceiver | |
// `type T`: *ConcreteTypeTypeReceiver | |
// type ConcreteTypeTypeReceiver is not identical to type *ConcreteTypeTypeReceiver: result=false | |
} | |
{ | |
var x interface{} = ConcreteTypeTypeReceiver{1} | |
var y InterfaceType = ConcreteTypeTypeReceiver{1} | |
_, okX = x.(InterfaceType) | |
_, okY = y.(InterfaceType) | |
fmt.Printf("C | interface type | type | value | %t | %t\n", okX, okY) // true / true | |
// `if T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T` | |
// `dynamic type of x`: ConcreteTypeTypeReceiver | |
// `interface T`: InterfaceType | |
// ConcreteTypeTypeReceiver implements InterfaceType: result=true | |
} | |
{ | |
var x interface{} = &ConcreteTypeTypeReceiver{1} | |
var y InterfaceType = &ConcreteTypeTypeReceiver{1} | |
_, okX = x.(ConcreteTypeTypeReceiver) // panic: interface conversion: interface {} is *main.ConcreteTypeTypeReceiver, not main.ConcreteTypeTypeReceiver | |
_, okY = y.(ConcreteTypeTypeReceiver) // panic: interface conversion: main.InterfaceType is *main.ConcreteTypeTypeReceiver, not main.ConcreteTypeTypeReceiver | |
fmt.Printf("D | concrete type | type | pointer | %t | %t\n", okX, okY) // false / false | |
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;` | |
// `dynamic type of x`: *ConcreteTypeTypeReceiver | |
// `type T`: ConcreteTypeTypeReceiver | |
// type *ConcreteTypeTypeReceiver is not identical to type ConcreteTypeTypeReceiver: result=false | |
} | |
{ | |
var x interface{} = &ConcreteTypeTypeReceiver{1} | |
var y InterfaceType = &ConcreteTypeTypeReceiver{1} | |
_, okX = x.(*ConcreteTypeTypeReceiver) | |
_, okY = y.(*ConcreteTypeTypeReceiver) | |
fmt.Printf("E | pointer to concrete type | type | pointer | %t | %t\n", okX, okY) // true / true | |
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;` | |
// `dynamic type of x`: *ConcreteTypeTypeReceiver | |
// `type T`: *ConcreteTypeTypeReceiver | |
// type *ConcreteTypeTypeReceiver is identical to type *ConcreteTypeTypeReceiver: result=true | |
} | |
{ | |
var x interface{} = &ConcreteTypeTypeReceiver{1} | |
var y InterfaceType = &ConcreteTypeTypeReceiver{1} | |
_, okX = x.(InterfaceType) | |
_, okY = y.(InterfaceType) | |
fmt.Printf("F | interface type | type | pointer | %t | %t \n", okX, okY) // true / true | |
// `if T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T` | |
// `dynamic type of x`: *ConcreteTypeTypeReceiver | |
// `interface T`: InterfaceType | |
// *ConcreteTypeTypeReceiver implements InterfaceType: result=true | |
} | |
{ | |
var x interface{} = ConcreteTypePtrReceiver{1} | |
//var y InterfaceType = ConcreteTypePtrReceiver{1} // cannot use ConcreteTypePtrReceiver literal (type ConcreteTypePtrReceiver) as type InterfaceType in assignment: | |
// ConcreteTypePtrReceiver does not implement InterfaceType (someMethod method has pointer receiver) | |
// x is empty interface `interface{}` | |
// any type satisfies empty interface = no `compiler static check failure` here | |
// y is `InterfaceType` | |
// to satisfy `InterfaceType` interface a type should have `someMethod() int` method | |
// ConcreteTypePtrReceiver{} is value - it is not a pointer | |
// we defined `someMethod() int` method on ConcreteTypePtrReceiver to operate on pointer | |
// only pointer to ConcreteTypePtrReceiver{} has `someMethod() int` method | |
// ConcreteTypePtrReceiver{} does not have `someMethod() int` method | |
// ConcreteTypePtrReceiver{} cannot satisfy `InterfaceType` = `compiler static check failure` | |
_, okX = x.(ConcreteTypePtrReceiver) | |
// _, okY = y.(ConcreteTypePtrReceiver) // N/A - see above | |
fmt.Printf("G | concrete type | pointer | value | %t | `%s`\n", okX, "static check failure") // true / <static check failure> | |
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;` | |
// `dynamic type of x`: ConcreteTypePtrReceiver | |
// `type T`: ConcreteTypePtrReceiver | |
// type ConcreteTypePtrReceiver is identical to type ConcreteTypePtrReceiver: result=true | |
} | |
{ | |
var x interface{} = ConcreteTypePtrReceiver{1} | |
//var y InterfaceType = ConcreteTypePtrReceiver{1} // missing method someMethod - `compiler static check failure` | |
_, okX = x.(*ConcreteTypePtrReceiver) // panic: interface conversion: interface {} is main.ConcreteTypePtrReceiver, not *main.ConcreteTypePtrReceiver | |
// _, okY = y.(*ConcreteTypePtrReceiver) // N/A - see above | |
fmt.Printf("H | pointer to concrete type | pointer | value | %t | `%s`\n", okX, "static check failure") // false / <static check failure> | |
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;` | |
// `dynamic type of x`: ConcreteTypePtrReceiver | |
// `type T`: *ConcreteTypePtrReceiver | |
// type ConcreteTypePtrReceiver is not identical to type *ConcreteTypePtrReceiver: result=false | |
} | |
{ | |
var x interface{} = ConcreteTypePtrReceiver{1} | |
//var y InterfaceType = ConcreteTypePtrReceiver{1} // missing method someMethod - `compiler static check failure` | |
_, okX = x.(InterfaceType) // panic: interface conversion: main.ConcreteTypePtrReceiver is not main.InterfaceType: missing method someMethod | |
// _, okY = y.(InterfaceType) // N/A - see above | |
fmt.Printf("I | interface type | pointer | value | %t | `%s`\n", okX, "static check failure") // false / <static check failure> | |
// `if T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T` | |
// `dynamic type of x`: ConcreteTypePtrReceiver | |
// `interface T`: InterfaceType | |
// InterfaceType require the method `someMethod() int` to be implemented | |
// for `type ConcreteTypePtrReceiver struct...` | |
// the method `someMethod() int` is defined on `*ConcreteTypePtrReceiver` | |
// the method `someMethod() int` is NOT defined on `ConcreteTypePtrReceiver` | |
// ConcreteTypePtrReceiver does not implement InterfaceType (only *ConcreteTypePtrReceiver): result=false | |
} | |
{ | |
var x interface{} = &ConcreteTypePtrReceiver{1} | |
//var y InterfaceType = &ConcreteTypePtrReceiver{1} | |
_, okX = x.(ConcreteTypePtrReceiver) // panic: interface conversion: interface {} is *main.ConcreteTypePtrReceiver, not main.ConcreteTypePtrReceiver | |
// _, okY = y.(ConcreteTypePtrReceiver) // impossible type assertion: ConcreteTypePtrReceiver does not implement InterfaceType (someMethod method has pointer receiver) | |
// y is `InterfaceType` | |
// to satisfy `InterfaceType` interface a type should have `someMethod() int` method | |
// ConcreteTypePtrReceiver{} is value - it is not a pointer | |
// we defined `someMethod() int` method on ConcreteTypePtrReceiver to operate on pointer | |
// only pointer to ConcreteTypePtrReceiver{} has `someMethod() int` method | |
// ConcreteTypePtrReceiver{} does not have `someMethod() int` method | |
fmt.Printf("J | concrete type | pointer | pointer | %t | `%s`\n", okX, "static check failure") // false / <static check failure> | |
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;` | |
// `dynamic type of x`: *ConcreteTypePtrReceiver | |
// `type T`: ConcreteTypePtrReceiver | |
// type *ConcreteTypePtrReceiver is not identical to type ConcreteTypePtrReceiver: result=false | |
} | |
{ | |
var x interface{} = &ConcreteTypePtrReceiver{1} | |
var y InterfaceType = &ConcreteTypePtrReceiver{1} | |
_, okX = x.(*ConcreteTypePtrReceiver) | |
_, okY = y.(*ConcreteTypePtrReceiver) | |
fmt.Printf("K | pointer to concrete type | pointer | pointer | %t | %t\n", okX, okY) // true / true | |
// `if T is not an interface type, x.(T) asserts that the dynamic type of x is identical to the type T; T must implement the (interface) type of x;` | |
// `dynamic type of x`: *ConcreteTypePtrReceiver | |
// `type T`: *ConcreteTypePtrReceiver | |
// type *ConcreteTypePtrReceiver is identical to type *ConcreteTypePtrReceiver: result=true | |
} | |
{ | |
var x interface{} = &ConcreteTypePtrReceiver{1} | |
var y InterfaceType = &ConcreteTypePtrReceiver{1} | |
_, okX = x.(InterfaceType) | |
_, okY = y.(InterfaceType) | |
fmt.Printf("L | interface type | pointer | pointer | %t | %t \n", okX, okY) // true / true | |
// `if T is an interface type, x.(T) asserts that the dynamic type of x implements the interface T` | |
// `dynamic type of x`: *ConcreteTypePtrReceiver | |
// `interface T`: InterfaceType | |
// *ConcreteTypePtrReceiver implements InterfaceType: result=true | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment