<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Chapter 5 Data Structures on Go: Under the Hood</title><link>https://golang.design/under-the-hood/en/part2lang/ch05data/</link><description>Recent content in Chapter 5 Data Structures on Go: Under the Hood</description><generator>Hugo</generator><language>en</language><atom:link href="https://golang.design/under-the-hood/en/part2lang/ch05data/index.xml" rel="self" type="application/rss+xml"/><item><title>5.1 Arrays and Slices</title><link>https://golang.design/under-the-hood/en/part2lang/ch05data/slice/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch05data/slice/</guid><description>&lt;h1 id="51-arrays-and-slices"&gt;5.1 Arrays and Slices&lt;/h1&gt;
&lt;p&gt;Arrays and slices are the two most basic sequence types in Go. They look similar, yet their memory models differ, and grasping this one point explains in a single stroke all the &amp;ldquo;surprises&amp;rdquo; of append and the traps of slice aliasing. Both share a single theme: a small &lt;strong&gt;header&lt;/strong&gt; describing a stretch of contiguous backing memory. The differences lie entirely in what the header holds and who owns that memory. This section first lays out the layout clearly, then starts from the classic abstraction of the &amp;ldquo;dynamic array&amp;rdquo; to see how Go&amp;rsquo;s &lt;code&gt;append&lt;/code&gt; achieves amortized &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;&lt;math xmlns="http://www.w3.org/1998/Math/MathML"&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mi&gt;O&lt;/mi&gt;&lt;mo stretchy="false"&gt;(&lt;/mo&gt;&lt;mn&gt;1&lt;/mn&gt;&lt;mo stretchy="false"&gt;)&lt;/mo&gt;&lt;/mrow&gt;&lt;annotation encoding="application/x-tex"&gt;O(1)&lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class="katex-html" aria-hidden="true"&gt;&lt;span class="base"&gt;&lt;span class="strut" style="height:1em;vertical-align:-0.25em;"&gt;&lt;/span&gt;&lt;span class="mord mathnormal" style="margin-right:0.02778em;"&gt;O&lt;/span&gt;&lt;span class="mopen"&gt;(&lt;/span&gt;&lt;span class="mord"&gt;1&lt;/span&gt;&lt;span class="mclose"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;, and finally lands on aliasing and cross-language comparison, the corners we run into day to day. Strings, though they share the same origin as slices, are immutable and form a category of their own; we leave them to &lt;a href=".././string"&gt;5.2&lt;/a&gt; for dedicated discussion.&lt;/p&gt;</description></item><item><title>5.2 Strings and Zero-Copy Conversion</title><link>https://golang.design/under-the-hood/en/part2lang/ch05data/string/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch05data/string/</guid><description>&lt;h1 id="52-strings-and-zero-copy-conversion"&gt;5.2 Strings and Zero-Copy Conversion&lt;/h1&gt;
&lt;p&gt;Strings share their origin with slices: in the runtime both are &amp;ldquo;a header plus memory living elsewhere&amp;rdquo; (for the layout, see &lt;a href="https://golang.design/under-the-hood/en/part2lang/ch05data/slice/#511-%e4%b8%89%e7%a7%8d%e5%86%85%e5%ad%98%e5%b8%83%e5%b1%80"&gt;5.1.1&lt;/a&gt;). But a string is &lt;strong&gt;read-only and immutable&lt;/strong&gt;, which makes it its own category. Immutability buys us sharing and copy-free use, and it brings one direct cost: converting between &lt;code&gt;string&lt;/code&gt; and &lt;code&gt;[]byte&lt;/code&gt; copies the bytes by default. This section opens up that copy, looks at the cases where the compiler can elide it, then turns to the manual zero-copy tools Go 1.20 provides and the safety contract that comes with them.&lt;/p&gt;</description></item><item><title>5.3 Hash Tables: Principles and Security</title><link>https://golang.design/under-the-hood/en/part2lang/ch05data/map/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch05data/map/</guid><description>&lt;h1 id="53-hash-tables-principles-and-security"&gt;5.3 Hash Tables: Principles and Security&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Go&amp;rsquo;s &lt;code&gt;map&lt;/code&gt; underwent a rare, complete rewrite in 2024 alongside Go 1.24,
moving from the classic bucketed hash table it had used for fourteen years to an implementation based on Swiss Tables. This section first clarifies the general principles of hash tables
and the attack-and-defense around them, leaving the full story of the rewrite to &lt;a href=".././swisstable"&gt;5.4&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;map&lt;/code&gt; is one of only two generic containers Go provides (the other being slice). It is implemented by the runtime with the compiler assisting in layout,
and at its core it is a hash table. When the reader writes &lt;code&gt;m[k]&lt;/code&gt;, the compiler translates it into calls to the &lt;code&gt;runtime.mapaccess&lt;/code&gt;
and &lt;code&gt;runtime.mapassign&lt;/code&gt; family of functions; the real storage, lookup, and growth all happen inside the
&lt;code&gt;internal/runtime/maps&lt;/code&gt; package. This section first lays out the general principles of hash tables and the attack-and-defense around them, to ground the next section where we drop down to Go&amp;rsquo;s own
two generations of implementation (the classic bucketed design from 1.0 through 1.23, and the Swiss Table design from 1.24 onward). Only by understanding the trade-offs here
can we see why the latter was worth a rewrite that cut to the bone.&lt;/p&gt;</description></item><item><title>5.4 Swiss Table and the Go 1.24 Implementation</title><link>https://golang.design/under-the-hood/en/part2lang/ch05data/swisstable/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://golang.design/under-the-hood/en/part2lang/ch05data/swisstable/</guid><description>&lt;h1 id="54-swiss-table-and-the-go-124-implementation"&gt;5.4 Swiss Table and the Go 1.24 Implementation&lt;/h1&gt;
&lt;p&gt;&lt;a href=".././map"&gt;5.3&lt;/a&gt; laid out the general principles of hash tables and the attack-and-defense around them: the two routes for handling collisions, and the defense against hash flooding. This section comes down to Go&amp;rsquo;s own two generations of implementation. We first open up Swiss Table, a modern open-addressing design, then look at how Go 1.24 brought it to ground and what it replaced in the process, then derive from the implementation two language rules that follow from it, and finally place Go within the larger picture of the various hash tables out there.&lt;/p&gt;</description></item></channel></rss>