New example: enums

Fixes #513
This commit is contained in:
Eli Bendersky
2024-05-14 06:25:29 -07:00
parent 0d466e6c64
commit 0b921edddd
8 changed files with 326 additions and 3 deletions

View File

@@ -19,6 +19,7 @@ Strings and Runes
Structs
Methods
Interfaces
Enums
Struct Embedding
Generics
Errors

75
examples/enums/enums.go Normal file
View File

@@ -0,0 +1,75 @@
// _Enumerated types_ (enums) are a special case of
// [sum types](https://en.wikipedia.org/wiki/Algebraic_data_type).
// 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.
package main
import "fmt"
// Our enum type `ServerState` has an underlying `int` type.
type ServerState int
// The possible values for `ServerState` are defined as
// constants. The special keyword [iota](https://go.dev/ref/spec#Iota)
// generates successive constant values automatically; in this
// case 0, 1, 2 and so on.
const (
StateIdle = iota
StateConnected
StateError
StateRetrying
)
// By implementing the [fmt.Stringer](https://pkg.go.dev/fmt#Stringer)
// interface, values of `StateType` can be printed out or converted
// to strings.
//
// This can get cumbersome if there are many possible values. In such
// cases the [stringer tool](https://pkg.go.dev/golang.org/x/tools/cmd/stringer)
// can be used in conjunction with `go:generate` to automate the
// process. See [this post](https://eli.thegreenplace.net/2021/a-comprehensive-guide-to-go-generate)
// for a longer explanation.
var stateName = map[ServerState]string{
StateIdle: "idle",
StateConnected: "connected",
StateError: "error",
StateRetrying: "retrying",
}
func (ss ServerState) String() string {
return stateName[ss]
}
func main() {
ns := transition(StateIdle)
fmt.Println(ns)
// If we have a value of type `int`, we cannot pass it to `transition` - the
// compiler will complain about type mismatch. This provides some degree of
// compile-time type safety for enums.
ns2 := transition(ns)
fmt.Println(ns2)
}
// transition emulates a state transition for a
// server; it takes the existing state and returns
// a new state.
func transition(s ServerState) ServerState {
switch s {
case StateIdle:
return StateConnected
case StateConnected, StateRetrying:
// Suppose we check some predicates here to
// determine the next state...
return StateIdle
case StateError:
return StateError
default:
panic(fmt.Errorf("unwknown state: %s", s))
}
return StateConnected
}

View File

@@ -0,0 +1,2 @@
1c5bf51fa651a25eb6d9d2d24cf7dbd2713aca0c
-6dSwyy83xj

3
examples/enums/enums.sh Normal file
View File

@@ -0,0 +1,3 @@
$ go run enums.go
connected
idle

240
public/enums generated Normal file
View File

@@ -0,0 +1,240 @@
<!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&rsquo;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/-6dSwyy83xj"><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">
<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="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>StateType</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">&#34;idle&#34;</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">&#34;connected&#34;</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">&#34;error&#34;</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">&#34;retrying&#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">
</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&hellip;</p>
</td>
<td class="code leading">
<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">&#34;unwknown state: %s&#34;</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></code></pre>
</td>
</tr>
<tr>
<td class="docs">
</td>
<td class="code">
<pre class="chroma"><code><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="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">Struct Embedding</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 ServerState int\u000A');codeLines.push('const (\u000A StateIdle \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(\"unwknown state: %s\", s))\u000A }\u000A');codeLines.push(' return StateConnected\u000A}\u000A');codeLines.push('');
</script>
<script src="site.js" async></script>
</body>
</html>

2
public/index.html generated
View File

@@ -69,6 +69,8 @@
<li><a href="interfaces">Interfaces</a></li>
<li><a href="enums">Enums</a></li>
<li><a href="struct-embedding">Struct Embedding</a></li>
<li><a href="generics">Generics</a></li>

4
public/interfaces generated
View File

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

View File

@@ -12,7 +12,7 @@
}
if (e.key == "ArrowLeft") {
window.location.href = 'interfaces';
window.location.href = 'enums';
}