234 lines
12 KiB
Plaintext
Generated
234 lines
12 KiB
Plaintext
Generated
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Go by Example: Struct 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 = 'generics';
|
|
}
|
|
|
|
}
|
|
</script>
|
|
<body>
|
|
<div class="example" id="struct-embedding">
|
|
<h2><a href="./">Go by Example</a>: Struct Embedding</h2>
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>Go supports <em>embedding</em> of structs and interfaces
|
|
to express a more seamless <em>composition</em> of types.
|
|
This is not to be confused with <a href="embed-directive"><code>//go:embed</code></a> which is
|
|
a go directive introduced in Go version 1.16+ to embed
|
|
files and folders into the application binary.</p>
|
|
|
|
</td>
|
|
<td class="code empty leading">
|
|
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
<a href="https://go.dev/play/p/-LOu1L0i2tR"><img title="Run code" src="play.png" class="run" /></a><img title="Copy code" src="clipboard.png" class="copy" />
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kn">import</span> <span class="s">"fmt"</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">base</span> <span class="kd">struct</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">num</span> <span class="kt">int</span>
|
|
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><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></span><span class="line"><span class="cl"> <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></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></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"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">container</span> <span class="kd">struct</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">base</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">str</span> <span class="kt">string</span>
|
|
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span></span></span></code></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"><code><span class="line"><span class="cl"> <span class="nx">co</span> <span class="o">:=</span> <span class="nx">container</span><span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">base</span><span class="p">:</span> <span class="nx">base</span><span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">num</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">str</span><span class="p">:</span> <span class="s">"some name"</span><span class="p">,</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span></span></span></code></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"><code><span class="line"><span class="cl"> <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></span></span></code></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"><code><span class="line"><span class="cl"> <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></span></span></code></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"><code><span class="line"><span class="cl"> <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></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="kd">type</span> <span class="nx">describer</span> <span class="kd">interface</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nf">describe</span><span class="p">()</span> <span class="kt">string</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="p">}</span></span></span></code></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"><code><span class="line"><span class="cl"> <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></span><span class="line"><span class="cl"> <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></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
|
|
</td>
|
|
<td class="code">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="gp">$</span> go run struct-embedding.go
|
|
</span></span><span class="line"><span class="cl"><span class="go">co={num: 1, str: some name}
|
|
</span></span></span><span class="line"><span class="cl"><span class="go">also num: 1
|
|
</span></span></span><span class="line"><span class="cl"><span class="go">describe: base with num=1
|
|
</span></span></span><span class="line"><span class="cl"><span class="go">describer: base with num=1</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
|
<p class="next">
|
|
Next example: <a href="generics">Generics</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>
|