Add example of struct embedding in Go
Also mention implementing interfaces with embedding Fixes #381 Fixes #398
This commit is contained in:
parent
f09cadcbd9
commit
35ad9cc35c
@ -18,6 +18,7 @@ Pointers
|
||||
Structs
|
||||
Methods
|
||||
Interfaces
|
||||
Embedding
|
||||
Errors
|
||||
Goroutines
|
||||
Channels
|
||||
|
59
examples/embedding/embedding.go
Normal file
59
examples/embedding/embedding.go
Normal 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())
|
||||
}
|
2
examples/embedding/embedding.hash
Normal file
2
examples/embedding/embedding.hash
Normal file
@ -0,0 +1,2 @@
|
||||
8a15291c6e82b9c6873002e2aa5cef65907a3405
|
||||
Xtg07j06zBv
|
5
examples/embedding/embedding.sh
Normal file
5
examples/embedding/embedding.sh
Normal 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
248
public/embedding
generated
Normal 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">"fmt"</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">"base with num=%v"</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">"some name"</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
</pre>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="docs">
|
||||
<p>We can access the base’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">"co={num: %v, str: %v}\n"</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">"also num:"</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">"describe:"</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">"describer:"</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
2
public/errors
generated
@ -9,7 +9,7 @@
|
||||
onkeydown = (e) => {
|
||||
|
||||
if (e.key == "ArrowLeft") {
|
||||
window.location.href = 'interfaces';
|
||||
window.location.href = 'embedding';
|
||||
}
|
||||
|
||||
|
||||
|
2
public/index.html
generated
2
public/index.html
generated
@ -67,6 +67,8 @@
|
||||
|
||||
<li><a href="interfaces">Interfaces</a></li>
|
||||
|
||||
<li><a href="embedding">Embedding</a></li>
|
||||
|
||||
<li><a href="errors">Errors</a></li>
|
||||
|
||||
<li><a href="goroutines">Goroutines</a></li>
|
||||
|
4
public/interfaces
generated
4
public/interfaces
generated
@ -14,7 +14,7 @@
|
||||
|
||||
|
||||
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">
|
||||
Next example: <a href="errors">Errors</a>.
|
||||
Next example: <a href="embedding">Embedding</a>.
|
||||
</p>
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user