gobyexample/public/struct-embedding

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">&#34;fmt&#34;</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">&#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></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">&#34;some name&#34;</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&rsquo;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">&#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></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">&#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></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">&#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></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">&#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></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>