Tmp: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
Line 1: Line 1:
==Example==
The example that follows shows how a type <tt>B</tt> implements interface <tt>A</tt>:
<pre>
//
// The interface A declares an interface method set containing a single method m()
//
type A interface {
    m()
}
//
// At this point, the type B is not yet linked to the interface A in any way.
// Its method set is empty, so it does not implement interface A, it does not
// implement any interface.
//
type B struct {
    i int
}
//
// We make B implement interface A by declaring B as a value receiver for m().
// This means B's method set includes now m() and it is a superset of A's method
// set.
//
func (b B) m() {
    // simply reports the value of i
    fmt.Println(b.i)
}
...
//
// B now implements A, so B instances can be assigned to A variables
//
var a A
a = B{1}
a.m()
//
// *B now also implements A, because the method set of the pointer type
// includes the methods declared agains the value  so *B instances
// can be assigned to A variables
//
var a2 A
a2 = &B{2}
a2.m()
...
</pre>
===A Variation of the Example===
Note that if in the example above we declare
<pre>
func (b *B) m() {
    ...
}
</pre>
instead of
<pre>
func (b B) m() {
    ...
}
</pre>
then the <tt>a = B{1}</tt> assignment would fail to compile with:
<pre>
./main.go:23: cannot use B literal (type B) as type A in assignment:
B does not implement A (m method has pointer receiver)
</pre>
This is because the type B does not implement the interface, because m() is not in the type B method set.
However, if we try:
<pre>
var a A
a = &B{1}
a.m()
</pre>
it works in both cases, because the method set associated with the B pointers include both <tt>func (b B) m() ...</tt> and <tt>func (b *B) m() ...</tt> so the pointer type B implements the interface.
==Passing Interfaces to Functions==
==Passing Interfaces to Functions==



Revision as of 22:33, 13 August 2024

Passing Interfaces to Functions

Interfaces can be used as arguments to functions. Passing an interface instance insures that the function body can rely on the fact the interface methods are available on the passed instance.

With the example above, we declare a function f() that expects an interface A and we pass a B instance when invoking the function:

...

type A interface {
    m()
}

func (b B) m() {
    ...
}

func f(a A) {
    a.m()
}

...
b := B{1}
f(b)
...

Note that the B instance can be passed by value (as in the example above) or by reference (as in the example below). Both cases work for reasons explained in the Method Set associated with the Pointers of a Type section:

...
b := B{1}
f(&b)
...

or (same thing)

...
bPtr := new(B)
f(bPtr)
...

Interfaces as Fields

Interfaces can be used as fields in structs.

Implementation Details

An interface variable is a two-word data structure.

The first word contains a pointer to an internal table called iTable, which contains type information about the stored value: the concrete type of the value that has been stored and a list of methods associated with the value. The second word is a reference to the stored value.

The combination of type information and pointer binds the relationship between the two values.

DEPLETE: Go Concepts - The Type System