240 lines
13 KiB
Plaintext
Generated
240 lines
13 KiB
Plaintext
Generated
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Go by Example: Enums</title>
|
|
<link rel=stylesheet href="site.css">
|
|
</head>
|
|
<script>
|
|
window.onkeydown = (e) => {
|
|
if (e.ctrlKey || e.altKey || e.shiftKey) {
|
|
return;
|
|
}
|
|
|
|
if (e.key == "ArrowLeft") {
|
|
window.location.href = 'interfaces';
|
|
}
|
|
|
|
|
|
if (e.key == "ArrowRight") {
|
|
window.location.href = 'struct-embedding';
|
|
}
|
|
|
|
}
|
|
</script>
|
|
<body>
|
|
<div class="example" id="enums">
|
|
<h2><a href="./">Go by Example</a>: Enums</h2>
|
|
|
|
<table>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p><em>Enumerated types</em> (enums) are a special case of
|
|
<a href="https://en.wikipedia.org/wiki/Algebraic_data_type">sum types</a>.
|
|
An enum is a type that has a fixed number of possible
|
|
values, each with a distinct name. Go doesn’t have an
|
|
enum type as a distinct language feature, but enums
|
|
are simple to implement using existing language idioms.</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/prQMptP_p1s"><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">
|
|
<p>Our enum type <code>ServerState</code> has an underlying <code>int</code> type.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">ServerState</span> <span class="kt">int</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>The possible values for <code>ServerState</code> are defined as
|
|
constants. The special keyword <a href="https://go.dev/ref/spec#Iota">iota</a>
|
|
generates successive constant values automatically; in this
|
|
case 0, 1, 2 and so on.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">const</span> <span class="p">(</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">StateIdle</span> <span class="nx">ServerState</span> <span class="p">=</span> <span class="kc">iota</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">StateConnected</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">StateError</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">StateRetrying</span>
|
|
</span></span><span class="line"><span class="cl"><span class="p">)</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>By implementing the <a href="https://pkg.go.dev/fmt#Stringer">fmt.Stringer</a>
|
|
interface, values of <code>ServerState</code> can be printed out or converted
|
|
to strings.</p>
|
|
|
|
<p>This can get cumbersome if there are many possible values. In such
|
|
cases the <a href="https://pkg.go.dev/golang.org/x/tools/cmd/stringer">stringer tool</a>
|
|
can be used in conjunction with <code>go:generate</code> to automate the
|
|
process. See <a href="https://eli.thegreenplace.net/2021/a-comprehensive-guide-to-go-generate">this post</a>
|
|
for a longer explanation.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">stateName</span> <span class="p">=</span> <span class="kd">map</span><span class="p">[</span><span class="nx">ServerState</span><span class="p">]</span><span class="kt">string</span><span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">StateIdle</span><span class="p">:</span> <span class="s">"idle"</span><span class="p">,</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">StateConnected</span><span class="p">:</span> <span class="s">"connected"</span><span class="p">,</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">StateError</span><span class="p">:</span> <span class="s">"error"</span><span class="p">,</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nx">StateRetrying</span><span class="p">:</span> <span class="s">"retrying"</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">
|
|
|
|
</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">ss</span> <span class="nx">ServerState</span><span class="p">)</span> <span class="nf">String</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">stateName</span><span class="p">[</span><span class="nx">ss</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>If we have a value of type <code>int</code>, we cannot pass it to <code>transition</code> - the
|
|
compiler will complain about type mismatch. This provides some degree of
|
|
compile-time type safety for enums.</p>
|
|
|
|
</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><span class="line"><span class="cl"> <span class="nx">ns</span> <span class="o">:=</span> <span class="nf">transition</span><span class="p">(</span><span class="nx">StateIdle</span><span class="p">)</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="nx">ns</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="nx">ns2</span> <span class="o">:=</span> <span class="nf">transition</span><span class="p">(</span><span class="nx">ns</span><span class="p">)</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="nx">ns2</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>transition emulates a state transition for a
|
|
server; it takes the existing state and returns
|
|
a new state.</p>
|
|
|
|
</td>
|
|
<td class="code leading">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">transition</span><span class="p">(</span><span class="nx">s</span> <span class="nx">ServerState</span><span class="p">)</span> <span class="nx">ServerState</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">switch</span> <span class="nx">s</span> <span class="p">{</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="nx">StateIdle</span><span class="p">:</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">StateConnected</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="nx">StateConnected</span><span class="p">,</span> <span class="nx">StateRetrying</span><span class="p">:</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td class="docs">
|
|
<p>Suppose we check some predicates here to
|
|
determine the next state…</p>
|
|
|
|
</td>
|
|
<td class="code">
|
|
|
|
<pre class="chroma"><code><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">StateIdle</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="nx">StateError</span><span class="p">:</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">StateError</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="k">default</span><span class="p">:</span>
|
|
</span></span><span class="line"><span class="cl"> <span class="nb">panic</span><span class="p">(</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">"unknown state: %s"</span><span class="p">,</span> <span class="nx">s</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="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 enums.go
|
|
</span></span><span class="line"><span class="cl"><span class="go">connected
|
|
</span></span></span><span class="line"><span class="cl"><span class="go">idle</span></span></span></code></pre>
|
|
</td>
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
|
|
<p class="next">
|
|
Next example: <a href="struct-embedding" rel="next">Struct Embedding</a>.
|
|
</p>
|
|
|
|
|
|
<p class="footer">
|
|
Based on
|
|
<em><a href="https://gobyexample.com/">Go by Example</a></em>
|
|
by <a href="https://markmcgranaghan.com">Mark McGranaghan</a>
|
|
and <a href="https://eli.thegreenplace.net">Eli Bendersky</a>,
|
|
licensed under
|
|
<a href="https://creativecommons.org/licenses/by/3.0/">CC BY 3.0</a>.
|
|
<a href="https://git.inkch.xyz/inkch/gobyexample/commit/7123d715f43f2880034db62116a476c01499cae9">
|
|
Style modifications by inkch
|
|
</a>.
|
|
<a href="https://github.com/mmcgrana/gobyexample">Original source</a>.
|
|
</p>
|
|
|
|
</div>
|
|
<script>
|
|
var codeLines = [];
|
|
codeLines.push('');codeLines.push('package main\u000A');codeLines.push('import \"fmt\"\u000A');codeLines.push('type ServerState int\u000A');codeLines.push('const (\u000A StateIdle ServerState \u003D iota\u000A StateConnected\u000A StateError\u000A StateRetrying\u000A)\u000A');codeLines.push('var stateName \u003D map[ServerState]string{\u000A StateIdle: \"idle\",\u000A StateConnected: \"connected\",\u000A StateError: \"error\",\u000A StateRetrying: \"retrying\",\u000A}\u000A');codeLines.push('func (ss ServerState) String() string {\u000A return stateName[ss]\u000A}\u000A');codeLines.push('func main() {\u000A ns :\u003D transition(StateIdle)\u000A fmt.Println(ns)\u000A');codeLines.push(' ns2 :\u003D transition(ns)\u000A fmt.Println(ns2)\u000A}\u000A');codeLines.push('func transition(s ServerState) ServerState {\u000A switch s {\u000A case StateIdle:\u000A return StateConnected\u000A case StateConnected, StateRetrying:\u000A');codeLines.push(' return StateIdle\u000A case StateError:\u000A return StateError\u000A default:\u000A panic(fmt.Errorf(\"unknown state: %s\", s))\u000A }\u000A}\u000A');codeLines.push('');
|
|
</script>
|
|
<script src="site.js" async></script>
|
|
</body>
|
|
</html>
|