-
Notifications
You must be signed in to change notification settings - Fork 168
/
conversion_1.go
103 lines (79 loc) · 3.08 KB
/
conversion_1.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// ---------------------
// Interface Conversions
// ---------------------
package main
import "fmt"
// Mover provides support for moving things.
type Mover interface {
Move()
}
// Locker provides support for locking and unlocking things.
type Locker interface {
Lock()
Unlock()
}
// MoveLocker provides support for moving and locking things.
type MoveLocker interface {
Mover
Locker
}
// bike represents a concrete type for the example.
type bike struct{}
// Move can change the position of a bike.
func (bike) Move() {
fmt.Println("Moving the bike")
}
// Lock prevents a bike from moving.
func (bike) Lock() {
fmt.Println("Locking the bike")
}
// Unlock allows a bike to be moved.
func (bike) Unlock() {
fmt.Println("Unlocking the bike")
}
func main() {
// Declare variables of the MoveLocker and Mover interfaces set to their zero value.
var ml MoveLocker
var m Mover
// Create a value of type bike and assign the value to the MoveLocker interface value.
ml = bike{}
// An interface value of type MoveLocker can be implicitly converted into
// a value of type Mover. They both declare a method named move.
m = ml
// ml m
// ------ ------
// | bike | bike | bike |
// ------ ------ ------
// | * | ---> | | <--- | * |
// ------ ------ ------
// However, we cannot go in the other direction, like so:
// ml = m
// The compiler will say:
// cannot use m (type Mover) as type MoveLocker in assignment: Mover does not
// implement MoveLocker (missing Lock method).
// --------------
// Type assertion
// --------------
// Interface type Mover does not declare methods named lock and unlock. Therefore, the compiler
// can't perform an implicit conversion to assign a value of interface type Mover to an
// interface value of type MoveLocker. It is irrelevant that the concrete type value of
// type bike that is stored inside of the Mover interface value implements the MoveLocker interface.
// We can perform a type assertion at runtime to support the assignment.
// Perform a type assertion against the Mover interface value to access a COPY of the concrete type
// value of type bike that was stored inside of it. Then assign the COPY of the concrete type
// to the MoveLocker interface.
// This is the syntax for type assertion.
// We are taking the interface value itself, dot (bike). We are using bike as an parameter.
// If m is not nil and there is a bike inside of m, we will get a copy of it since we are using value semantic.
// Or else, a panic occurs.
// b is having a copy of bike value.
b := m.(bike)
// We can prevent panic when type assertion breaks by destructuring
// the boolean value that represents type assertion result
b, ok := m.(bike)
fmt.Println("Does m has value of bike?:", ok)
ml = b
// It's important to note that the type assertion syntax provides a way to state what type
// of value is stored inside the interface. This is more powerful from a language and readability
// standpoint, than using a casting syntax, like in other languages.
}