<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Beginners on PHP Boy Scout</title><link>https://blog-570662.gitlab.io/tags/beginners/</link><description>Recent content in Beginners on PHP Boy Scout</description><generator>Hugo -- gohugo.io</generator><language>en-gb</language><copyright>Matt Cockayne</copyright><lastBuildDate>Tue, 21 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://blog-570662.gitlab.io/tags/beginners/index.xml" rel="self" type="application/rss+xml"/><item><title>Just enough Rust to follow along</title><link>https://blog-570662.gitlab.io/just-enough-rust-to-follow-along/</link><pubDate>Tue, 21 Apr 2026 00:00:00 +0000</pubDate><guid>https://blog-570662.gitlab.io/just-enough-rust-to-follow-along/</guid><description>&lt;img src="https://blog-570662.gitlab.io/just-enough-rust-to-follow-along/cover-just-enough-rust-to-follow-along.png" alt="Featured image of post Just enough Rust to follow along" /&gt;&lt;p&gt;I&amp;rsquo;m about to write a run of posts about building rust-tool-base, and they lean on a handful of Rust ideas that I&amp;rsquo;d otherwise have to keep stopping to explain. So here they are, up front, in one place. You don&amp;rsquo;t need to write Rust to follow the series. You need a feel for maybe six concepts, and this is a quick, friendly tour of them. If you already write Rust, skip it with my blessing.&lt;/p&gt;
&lt;h2 id="ownership-and-borrowing"&gt;Ownership and borrowing
&lt;/h2&gt;&lt;p&gt;This is the one everybody mentions, and the one the whole language is built around. Every value in Rust has exactly one &lt;em&gt;owner&lt;/em&gt;, and when the owner goes away, the value is cleaned up. No garbage collector deciding when, no manual &lt;code&gt;free&lt;/code&gt;. If you want to let another piece of code use a value without handing over ownership, you &lt;em&gt;borrow&lt;/em&gt; it: &lt;code&gt;&amp;amp;thing&lt;/code&gt; lends it out for reading, &lt;code&gt;&amp;amp;mut thing&lt;/code&gt; for writing, and the compiler enforces that you can&amp;rsquo;t, say, change something while someone else is reading it.&lt;/p&gt;
&lt;p&gt;The payoff, and the reason people put up with the up-front fuss, is that an entire family of bug (use-after-free, data races, dangling pointers) becomes a &lt;em&gt;compile&lt;/em&gt; error rather than a 3am one. When a post says something &amp;ldquo;moves&amp;rdquo; or is &amp;ldquo;borrowed&amp;rdquo;, that&amp;rsquo;s all this is.&lt;/p&gt;
&lt;h2 id="traits-are-rusts-interfaces"&gt;Traits are Rust&amp;rsquo;s interfaces
&lt;/h2&gt;&lt;p&gt;A &lt;em&gt;trait&lt;/em&gt; is a named set of methods a type can promise to provide, exactly like an interface in Go or Java. &lt;code&gt;impl Command for Greet { ... }&lt;/code&gt; reads as &amp;ldquo;the &lt;code&gt;Greet&lt;/code&gt; type fulfils the &lt;code&gt;Command&lt;/code&gt; contract.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Two bits of syntax show up a lot. &lt;code&gt;dyn Command&lt;/code&gt; means &amp;ldquo;some value whose concrete type I don&amp;rsquo;t know, but which implements &lt;code&gt;Command&lt;/code&gt;&amp;rdquo;, decided at runtime. And because the compiler needs a known size, you usually see it wrapped: &lt;code&gt;Box&amp;lt;dyn Command&amp;gt;&lt;/code&gt; is &amp;ldquo;a pointer to some &lt;code&gt;Command&lt;/code&gt;, whatever it turns out to be.&amp;rdquo; Whenever the series talks about a registry of &lt;code&gt;Box&amp;lt;dyn Something&amp;gt;&lt;/code&gt;, it just means a list of different types that all satisfy the same trait.&lt;/p&gt;
&lt;h2 id="enums-match-and-non_exhaustive"&gt;Enums, &lt;code&gt;match&lt;/code&gt;, and &lt;code&gt;#[non_exhaustive]&lt;/code&gt;
&lt;/h2&gt;&lt;p&gt;A Rust &lt;code&gt;enum&lt;/code&gt; is more than a list of named numbers; it&amp;rsquo;s a proper &amp;ldquo;one of these&amp;rdquo; type, and each variant can carry its own data. You handle one with &lt;code&gt;match&lt;/code&gt;, which is like a &lt;code&gt;switch&lt;/code&gt; that the compiler &lt;em&gt;forces&lt;/em&gt; you to make complete: miss a case and it won&amp;rsquo;t build.&lt;/p&gt;
&lt;p&gt;That completeness is usually a gift, but it&amp;rsquo;s awkward for a library, because adding a new variant would break everyone&amp;rsquo;s &lt;code&gt;match&lt;/code&gt;. The fix is the attribute &lt;code&gt;#[non_exhaustive]&lt;/code&gt;: it tells code outside the library &amp;ldquo;you must keep a catch-all &lt;code&gt;_ =&amp;gt;&lt;/code&gt; arm, because I reserve the right to add variants later.&amp;rdquo; With that in place, growing the enum is a non-breaking change. (One whole post turns on a subtle way to &lt;em&gt;accidentally&lt;/em&gt; cancel that promise.)&lt;/p&gt;
&lt;h2 id="the-type-system-carries-facts-not-just-shapes"&gt;The type system carries facts, not just shapes
&lt;/h2&gt;&lt;p&gt;Here&amp;rsquo;s an idea that surprises people coming from other languages: a Rust type often encodes &lt;em&gt;more&lt;/em&gt; than &amp;ldquo;this is a number&amp;rdquo; or &amp;ldquo;this is a list.&amp;rdquo; The size of a fixed array is part of its type, so &lt;code&gt;[Feature; 11]&lt;/code&gt; and &lt;code&gt;[Feature; 12]&lt;/code&gt; are genuinely different, incompatible types, not one type holding a different count.&lt;/p&gt;
&lt;p&gt;Pushed further, you can make the type track &lt;em&gt;state&lt;/em&gt;. A &amp;ldquo;typestate&amp;rdquo; builder changes type as you call it, so &lt;code&gt;.build()&lt;/code&gt; literally doesn&amp;rsquo;t exist as a method until every required field has been set, and forgetting one is a compile error rather than a runtime surprise. When a post says the compiler &amp;ldquo;won&amp;rsquo;t let you&amp;rdquo; do something, this is usually how: the mistake was made unrepresentable in the types.&lt;/p&gt;
&lt;h2 id="result-and-the--operator"&gt;&lt;code&gt;Result&lt;/code&gt; and the &lt;code&gt;?&lt;/code&gt; operator
&lt;/h2&gt;&lt;p&gt;Rust has no exceptions. A function that can fail returns a &lt;code&gt;Result&amp;lt;T, E&amp;gt;&lt;/code&gt;: either &lt;code&gt;Ok(value)&lt;/code&gt; or &lt;code&gt;Err(problem)&lt;/code&gt;, and you can&amp;rsquo;t use the value without acknowledging the error case. Writing that check by hand everywhere would be miserable, so there&amp;rsquo;s a shorthand: the &lt;code&gt;?&lt;/code&gt; operator. &lt;code&gt;let x = thing()?;&lt;/code&gt; means &amp;ldquo;if this returned an error, return it up to my caller right now; otherwise give me the value.&amp;rdquo; Errors travel up the call stack as ordinary return values until something handles them, or until they fall out of &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="crates-the-workspace-and-features"&gt;Crates, the workspace, and features
&lt;/h2&gt;&lt;p&gt;A &lt;em&gt;crate&lt;/em&gt; is Rust&amp;rsquo;s unit of compilation, roughly &amp;ldquo;a library or binary.&amp;rdquo; A &lt;em&gt;workspace&lt;/em&gt; is a bundle of crates built together, which is how rust-tool-base is laid out: &lt;code&gt;rtb-app&lt;/code&gt;, &lt;code&gt;rtb-cli&lt;/code&gt;, &lt;code&gt;rtb-config&lt;/code&gt; and so on, each its own crate. And &lt;em&gt;Cargo features&lt;/em&gt; are compile-time switches declared in &lt;code&gt;Cargo.toml&lt;/code&gt;: turn a feature off and the code it guards, and any dependency it pulled in, is never compiled into your binary at all. Not disabled at runtime; simply absent. That distinction does real work in one of the posts.&lt;/p&gt;
&lt;h2 id="thats-the-toolkit"&gt;That&amp;rsquo;s the toolkit
&lt;/h2&gt;&lt;p&gt;Ownership and borrowing, traits and &lt;code&gt;dyn&lt;/code&gt;, enums and &lt;code&gt;match&lt;/code&gt; and &lt;code&gt;#[non_exhaustive]&lt;/code&gt;, types that carry facts, &lt;code&gt;Result&lt;/code&gt; and &lt;code&gt;?&lt;/code&gt;, and crates with features. Six ideas, and they&amp;rsquo;re enough to read everything else in this series without tripping over the language itself. Where a post needs a seventh thing, it&amp;rsquo;ll explain it in passing. Now, on with the actual building.&lt;/p&gt;</description></item></channel></rss>