Add example of struct embedding in Go

Also mention implementing interfaces with embedding

Fixes #381
Fixes #398
This commit is contained in:
Eli Bendersky 2021-11-22 12:48:11 -08:00
parent f09cadcbd9
commit 35ad9cc35c
8 changed files with 320 additions and 3 deletions

View File

@ -18,6 +18,7 @@ Pointers
Structs Structs
Methods Methods
Interfaces Interfaces
Embedding
Errors Errors
Goroutines Goroutines
Channels Channels

View File

@ -0,0 +1,59 @@
// Go support _embedding_ of structs and interfaces
// to express a more seamless _composition_ of types.
package main
import "fmt"
type base struct {
num int
}
func (b base) describe() string {
return fmt.Sprintf("base with num=%v", b.num)
}
// A `container` _embeds_ a `base`. An embedding looks
// like a field without a name.
type container struct {
base
str string
}
func main() {
// When creating structs with literals, we have to
// initialize the embedding explicitly; here the
// embedded type serves as the field name.
co := container{
base: base{
num: 1,
},
str: "some name",
}
// We can access the base's fields directly on `co`,
// e.g. `co.num`.
fmt.Printf("co={num: %v, str: %v}\n", co.num, co.str)
// Alternatively, we can spell out the full path using
// the embedded type name.
fmt.Println("also num:", co.base.num)
// Since `container` embeds `base`, the methods of
// `base` also become methods of a `container`. Here
// we invoke a method that was embedded from `base`
// directly on `co`.
fmt.Println("describe:", co.describe())
type describer interface {
describe() string
}
// Embedding structs with methods may be used to bestow
// interface implementations onto other structs. Here
// we see that a `container` now implements the
// `describer` interface because it embeds `base`.
var d describer = co
fmt.Println("describer:", d.describe())
}

View File

@ -0,0 +1,2 @@
8a15291c6e82b9c6873002e2aa5cef65907a3405
Xtg07j06zBv

View File

@ -0,0 +1,5 @@
$ go run embedding.go
co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

248
public/embedding generated Normal file
View File

@ -0,0 +1,248 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Go by Example: Embedding</title>
<link rel=stylesheet href="site.css">
</head>
<script>
onkeydown = (e) => {
if (e.key == "ArrowLeft") {
window.location.href = 'interfaces';
}
if (e.key == "ArrowRight") {
window.location.href = 'errors';
}
}
</script>
<body>
<div class="example" id="embedding">
<h2><a href="./">Go by Example</a>: Embedding</h2>
<table>
<tr>
<td class="docs">
<p>Go support <em>embedding</em> of structs and interfaces
to express a more seamless <em>composition</em> of types.</p>
</td>
<td class="code empty leading">
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code leading">
<a href="http://play.golang.org/p/Xtg07j06zBv"><img title="Run code" src="play.png" class="run" /></a><img title="Copy code" src="clipboard.png" class="copy" />
<pre class="chroma"><span class="kn">package</span> <span class="nx">main</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code leading">
<pre class="chroma"><span class="kn">import</span> <span class="s">&#34;fmt&#34;</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code leading">
<pre class="chroma"><span class="kd">type</span> <span class="nx">base</span> <span class="kd">struct</span> <span class="p">{</span>
<span class="nx">num</span> <span class="kt">int</span>
<span class="p">}</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code leading">
<pre class="chroma"><span class="kd">func</span> <span class="p">(</span><span class="nx">b</span> <span class="nx">base</span><span class="p">)</span> <span class="nf">describe</span><span class="p">()</span> <span class="kt">string</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;base with num=%v&#34;</span><span class="p">,</span> <span class="nx">b</span><span class="p">.</span><span class="nx">num</span><span class="p">)</span>
<span class="p">}</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>A <code>container</code> <em>embeds</em> a <code>base</code>. An embedding looks
like a field without a name.</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="kd">type</span> <span class="nx">container</span> <span class="kd">struct</span> <span class="p">{</span>
<span class="nx">base</span>
<span class="nx">str</span> <span class="kt">string</span>
<span class="p">}</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code leading">
<pre class="chroma"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>When creating structs with literals, we have to
initialize the embedding explicitly; here the
embedded type serves as the field name.</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="nx">co</span> <span class="o">:=</span> <span class="nx">container</span><span class="p">{</span>
<span class="nx">base</span><span class="p">:</span> <span class="nx">base</span><span class="p">{</span>
<span class="nx">num</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="p">},</span>
<span class="nx">str</span><span class="p">:</span> <span class="s">&#34;some name&#34;</span><span class="p">,</span>
<span class="p">}</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>We can access the base&rsquo;s fields directly on <code>co</code>,
e.g. <code>co.num</code>.</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;co={num: %v, str: %v}\n&#34;</span><span class="p">,</span> <span class="nx">co</span><span class="p">.</span><span class="nx">num</span><span class="p">,</span> <span class="nx">co</span><span class="p">.</span><span class="nx">str</span><span class="p">)</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>Alternatively, we can spell out the full path using
the embedded type name.</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;also num:&#34;</span><span class="p">,</span> <span class="nx">co</span><span class="p">.</span><span class="nx">base</span><span class="p">.</span><span class="nx">num</span><span class="p">)</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>Since <code>container</code> embeds <code>base</code>, the methods of
<code>base</code> also become methods of a <code>container</code>. Here
we invoke a method that was embedded from <code>base</code>
directly on <code>co</code>.</p>
</td>
<td class="code leading">
<pre class="chroma">
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;describe:&#34;</span><span class="p">,</span> <span class="nx">co</span><span class="p">.</span><span class="nf">describe</span><span class="p">())</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code leading">
<pre class="chroma"> <span class="kd">type</span> <span class="nx">describer</span> <span class="kd">interface</span> <span class="p">{</span>
<span class="nf">describe</span><span class="p">()</span> <span class="kt">string</span>
<span class="p">}</span>
</pre>
</td>
</tr>
<tr>
<td class="docs">
<p>Embedding structs with methods may be used to bestow
interface implementations onto other structs. Here
we see that a <code>container</code> now implements the
<code>describer</code> interface because it embeds <code>base</code>.</p>
</td>
<td class="code">
<pre class="chroma">
<span class="kd">var</span> <span class="nx">d</span> <span class="nx">describer</span> <span class="p">=</span> <span class="nx">co</span>
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">&#34;describer:&#34;</span><span class="p">,</span> <span class="nx">d</span><span class="p">.</span><span class="nf">describe</span><span class="p">())</span>
<span class="p">}</span>
</pre>
</td>
</tr>
</table>
<table>
<tr>
<td class="docs">
</td>
<td class="code">
<pre class="chroma"><span class="gp">$</span> go run embedding.go
<span class="go">co={num: 1, str: some name}
</span><span class="go">also num: 1
</span><span class="go">describe: base with num=1
</span><span class="go">describer: base with num=1</span></pre>
</td>
</tr>
</table>
<p class="next">
Next example: <a href="errors">Errors</a>.
</p>
<p class="footer">
by <a href="https://markmcgranaghan.com">Mark McGranaghan</a> and <a href="https://eli.thegreenplace.net">Eli Bendersky</a> | <a href="https://github.com/mmcgrana/gobyexample">source</a> | <a href="https://github.com/mmcgrana/gobyexample#license">license</a>
</p>
</div>
<script>
var codeLines = [];
codeLines.push('');codeLines.push('package main\u000A');codeLines.push('import \"fmt\"\u000A');codeLines.push('type base struct {\u000A num int\u000A}\u000A');codeLines.push('func (b base) describe() string {\u000A return fmt.Sprintf(\"base with num\u003D%v\", b.num)\u000A}\u000A');codeLines.push('type container struct {\u000A base\u000A str string\u000A}\u000A');codeLines.push('func main() {\u000A');codeLines.push(' co :\u003D container{\u000A base: base{\u000A num: 1,\u000A },\u000A str: \"some name\",\u000A }\u000A');codeLines.push(' fmt.Printf(\"co\u003D{num: %v, str: %v}\\n\", co.num, co.str)\u000A');codeLines.push(' fmt.Println(\"also num:\", co.base.num)\u000A');codeLines.push(' fmt.Println(\"describe:\", co.describe())\u000A');codeLines.push(' type describer interface {\u000A describe() string\u000A }\u000A');codeLines.push(' var d describer \u003D co\u000A fmt.Println(\"describer:\", d.describe())\u000A}\u000A');codeLines.push('');
</script>
<script src="site.js" async></script>
</body>
</html>

2
public/errors generated
View File

@ -9,7 +9,7 @@
onkeydown = (e) => { onkeydown = (e) => {
if (e.key == "ArrowLeft") { if (e.key == "ArrowLeft") {
window.location.href = 'interfaces'; window.location.href = 'embedding';
} }

2
public/index.html generated
View File

@ -67,6 +67,8 @@
<li><a href="interfaces">Interfaces</a></li> <li><a href="interfaces">Interfaces</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="errors">Errors</a></li> <li><a href="errors">Errors</a></li>
<li><a href="goroutines">Goroutines</a></li> <li><a href="goroutines">Goroutines</a></li>

4
public/interfaces generated
View File

@ -14,7 +14,7 @@
if (e.key == "ArrowRight") { if (e.key == "ArrowRight") {
window.location.href = 'errors'; window.location.href = 'embedding';
} }
} }
@ -222,7 +222,7 @@ these structs as arguments to <code>measure</code>.</p>
<p class="next"> <p class="next">
Next example: <a href="errors">Errors</a>. Next example: <a href="embedding">Embedding</a>.
</p> </p>