From: Ralf Jung Date: Wed, 27 Sep 2023 11:48:51 +0000 (+0200) Subject: Merge pull request #42 from zdyxry/master X-Git-Url: https://git.ralfj.de/rust-101.git/commitdiff_plain/HEAD?hp=b47621b6c6db5d528eb315308cd4e67a2bf9e3cd Merge pull request #42 from zdyxry/master fix link to example --- diff --git a/Cargo.lock b/Cargo.lock index 3174aa5..c0bfd7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,4 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + [[package]] name = "rust-101" version = "0.1.0" - diff --git a/Makefile b/Makefile index c157dac..d8c0e44 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ docs: $(DOCFILES) @sed 's|^\(\s*//\)@|\1|;s|\s*/\*@\*/$$||;s|\(\s*\)\S.*/\*@@\*/|\1unimplemented!()|' $< | sed -f dup-unimpl.sed > $@ docs/%.html: .tmp/docs/%.rs - @./pycco-rs $< + ~/.local/pipx/venvs/pycco/bin/python pycco-rs $< ## Workspace # The generated files are shipped only for the benefit of Windows users, who diff --git a/README.md b/README.md index be0e4fb..494099f 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ The most accessible form of the tutorial is its ## Offline Usage You can either read through the sources in `src/`, or generate the -HTML in `docs/` using `make docs` (this step needs -[Pycco](https://pycco-docs.github.io/pycco/)). +HTML in `docs/` using `make docs`. This steps assumes `pipx install pycco` has +been run before; it will use the pipx-created venv to import pycco. The files `workspace/src/part*.rs` are generated by `make workspace`. diff --git a/pycco-rs b/pycco-rs index c884311..3e6b29d 100755 --- a/pycco-rs +++ b/pycco-rs @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # A little wrapper around pycco, to add Rust support. import pycco, pycco_resources from pygments import lexers, formatters @@ -32,13 +32,13 @@ def generate_documentation(*args, **kwargs): generate_documentation_called = True result = generate_documentation_orig(*args, **kwargs) # now patch it - result = patch_html(result, '', - '') - result = patch_html(result, '', 'Rust-101: ') + result = patch_html(result, b'<link rel="stylesheet" href="pycco.css">', + b'<link rel="stylesheet" href="pycco_custom.css"><meta name="viewport" content="width=device-width">') + result = patch_html(result, b'<title>', b'Rust-101: ') ## remove empty code blocks - result = re.sub('''<div class='code'> + result = re.sub(b'''<div class='code'> *<div class="highlight"><pre>(<span></span>)?</pre></div> - *</div>''', '<!-- empty code block -->', result) + *</div>''', b'<!-- empty code block -->', result) # done return result pycco.main.generate_documentation = generate_documentation diff --git a/solutions/Cargo.lock b/solutions/Cargo.lock index 577ad48..2141c1d 100644 --- a/solutions/Cargo.lock +++ b/solutions/Cargo.lock @@ -1,166 +1,168 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + [[package]] name = "aho-corasick" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" dependencies = [ - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] name = "docopt" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a" dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "regex", + "serde", + "serde_derive", + "strsim", ] [[package]] name = "lazy_static" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" [[package]] name = "libc" version = "0.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30885bcb161cf67054244d10d4a7f4835ffd58773bc72e07d35fecf472295503" [[package]] name = "memchr" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" dependencies = [ - "libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "quote" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" [[package]] name = "regex" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" dependencies = [ - "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", + "utf8-ranges", ] [[package]] name = "regex-syntax" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" [[package]] name = "serde" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a7c6b751a2e8d5df57a5ff71b5b4fc8aaee9ee28ff1341d640dd130bb5f4f7a" [[package]] name = "serde_derive" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f6ca58905ebd3c3b285a8a6d4f3ac92b92c0d7951d5649b1bdd212549c06639" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote", + "serde_derive_internals", + "syn", ] [[package]] name = "serde_derive_internals" version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a" dependencies = [ - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn", + "synom", ] [[package]] name = "solutions" version = "0.1.0" dependencies = [ - "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "docopt", ] [[package]] name = "strsim" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" [[package]] name = "syn" version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "quote", + "synom", + "unicode-xid", ] [[package]] name = "synom" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "thread_local" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "unreachable", ] [[package]] name = "unicode-xid" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" [[package]] name = "unreachable" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "void", ] [[package]] name = "utf8-ranges" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" [[package]] name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" -"checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a" -"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum libc 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "30885bcb161cf67054244d10d4a7f4835ffd58773bc72e07d35fecf472295503" -"checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" -"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" -"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7c6b751a2e8d5df57a5ff71b5b4fc8aaee9ee28ff1341d640dd130bb5f4f7a" -"checksum serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2f6ca58905ebd3c3b285a8a6d4f3ac92b92c0d7951d5649b1bdd212549c06639" -"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a" -"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" -"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/solutions/src/vec.rs b/solutions/src/vec.rs index 8eff916..faf5171 100644 --- a/solutions/src/vec.rs +++ b/solutions/src/vec.rs @@ -37,7 +37,7 @@ pub mod part01 { } } -pub mod part0203 { +pub mod part02 { // A polymorphic (generic) "some value, or no value" pub enum SomethingOrNothing<T> { Something(T), @@ -125,3 +125,63 @@ pub mod part0203 { } } +pub mod part03 { + use std::io::prelude::*; + use std::io; + + fn read_vec() -> Vec<i32> { + let mut vec: Vec<i32> = Vec::<i32>::new(); + let stdin = io::stdin(); + println!("Enter a list of numbers, one per line. End with Ctrl-D (Linux) or Ctrl-Z (Windows)."); + for line in stdin.lock().lines() { + let line = line.unwrap(); + match line.trim().parse::<i32>() { + Ok(num) => { + vec.push(num) + }, + // We don't care about the particular error, so we ignore it with a `_`. + Err(_) => { + println!("What did I say about numbers?") + }, + } + } + + vec + } + + use super::part02::{SomethingOrNothing,Something,Nothing,vec_min}; + + pub fn main() { + let vec = read_vec(); + let min = vec_min(vec); + min.print2(); + } + + pub trait Print { + fn print(self); + } + impl Print for i32 { + fn print(self) { + print!("{}", self); + } + } + + impl<T: Print> SomethingOrNothing<T> { + fn print2(self) { + match self { + Nothing => println!("The number is: <nothing>"), + Something(n) => { + print!("The number is: "); + n.print(); + println!(); + } + } + } + } + + impl Print for f32 { + fn print(self) { + print!("{}", self); + } + } +} diff --git a/src/main.rs b/src/main.rs index 2a0aa76..66a0ed7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -119,7 +119,7 @@ fn main() { // // * [The Rust Book](https://doc.rust-lang.org/stable/book/) // * [The Rustonomicon](https://doc.rust-lang.org/nightly/nomicon/) -// * [Rust by Example](http://rustbyexample.com/) +// * [Rust by Example](https://doc.rust-lang.org/rust-by-example/) // * The [Rust Subreddit](https://www.reddit.com/r/rust/) // * A [collection of links](https://github.com/ctjhoa/rust-learning) to blog posts, articles, // videos, etc. for learning Rust. diff --git a/src/part01.rs b/src/part01.rs index a4537ac..e00cf53 100644 --- a/src/part01.rs +++ b/src/part01.rs @@ -87,7 +87,7 @@ impl NumberOrNothing { //@ methods on an `enum` (and also on `struct`, which we will learn about later) //@ is independent of the definition of the type. `self` is like `this` in other //@ languages, and its type is always implicit. So `print` is now a method that -//@ takes as first argument a `NumberOrNothing`, just like `print_number_or_nothing`. +//@ takes `NumberOrNothing` as the first argument, just like `print_number_or_nothing`. //@ //@ Try making `number_or_default` from above an inherent method as well! diff --git a/src/part02.rs b/src/part02.rs index a24a9d0..2bf4d97 100644 --- a/src/part02.rs +++ b/src/part02.rs @@ -148,7 +148,7 @@ pub fn main() { //@ If this printed `3`, then your generic `vec_min` is working! So get ready for the next part. // **Exercise 02.1**: Change your program such that it computes the minimum of a `Vec<f32>` (where -// `f32` is the type // of 32-bit floating-point numbers). You should not change `vec_min` in any +// `f32` is the type of 32-bit floating-point numbers). You should not change `vec_min` in any // way, obviously! //@ [index](main.html) | [previous](part01.html) | [raw source](workspace/src/part02.rs) | diff --git a/src/part03.rs b/src/part03.rs index 44431e6..b81bbc3 100644 --- a/src/part03.rs +++ b/src/part03.rs @@ -99,9 +99,10 @@ pub fn main() { min.print(); /*@*/ } -// **Exercise 03.1**: Define a trait `Print` to write a generic version of -// `SomethingOrNothing::print`. -// Implement that trait for `i32`, and change the code above to use it. +// **Exercise 03.1**: The goal is to write a generic version of `SomethingOrNothing::print`. +// To this end, define a trait `Print` that provides (simple) generic printing, and implement +// that trait for `i32`. Then define `SomethingOrNothing::print2` to use that trait, and change +// `main` above to use the new generic `print2` function. // I will again provide a skeleton for this solution. It also shows how to attach bounds to generic // implementations (just compare it to the `impl` block from the previous exercise). // You can read this as "For all types `T` satisfying the `Print` trait, I provide an implementation @@ -114,6 +115,9 @@ pub fn main() { pub trait Print { /* Add things here */ } +impl Print for i32 { + /* Add things here */ +} impl<T: Print> SomethingOrNothing<T> { fn print2(self) { unimplemented!() diff --git a/src/part04.rs b/src/part04.rs index 21654cd..2381ff4 100644 --- a/src/part04.rs +++ b/src/part04.rs @@ -106,7 +106,7 @@ fn shared_ref_demo() { //@ their official name. //@ As an example, consider a function which increments every element of a vector by 1. -//@ The type `&mut Vec<i32>` is the type of mutable references to `vec<i32>`. Because the reference +//@ The type `&mut Vec<i32>` is the type of mutable references to `Vec<i32>`. Because the reference //@ is mutable, we can use a mutable iterator, providing mutable references to the elements. fn vec_inc(v: &mut Vec<i32>) { for e in v.iter_mut() { diff --git a/src/part06.rs b/src/part06.rs index 939fe08..4c7ee24 100644 --- a/src/part06.rs +++ b/src/part06.rs @@ -127,8 +127,8 @@ fn head<T>(v: &Vec<T>) -> Option<&T> { //@ have aliasing (of `first` and `v`) and mutation. But this time, the bug is hidden behind the //@ call to `head`. How does Rust solve this? If we translate the code above to Rust, it doesn't //@ compile, so clearly we are good - but how and why? -//@ (Notice that have to explicitly assert using //@ `unwrap` that `first` is not `None`, whereas -//@ the C++ code above would silently dereference a //@ `NULL`-pointer. But that's another point.) +//@ (Notice that we use `unwrap` to explicitly assert that `first` is not `None`, whereas +//@ the C++ code above would silently dereference a `NULL`-pointer. But that's another point.) fn rust_foo(mut v: Vec<i32>) -> i32 { let first: Option<&i32> = head(&v); /* v.push(42); */ diff --git a/src/part10.rs b/src/part10.rs index 39270de..2ba31f3 100644 --- a/src/part10.rs +++ b/src/part10.rs @@ -164,5 +164,13 @@ fn filter_vec_by_divisor(v: &Vec<i32>, divisor: i32) -> Vec<i32> { // those numbers that sit at odd positions? A function that checks whether a vector contains a // certain number? Whether all numbers are smaller than some threshold? Be creative! +// **Exercise 10.2**: We started the journey in Part 02 with `SomethingOrNothing<T>`, and later +// learned about `Option<T>` in Part 04. `Option<T>` also has a `map` function. +// [Read its documentation here.](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.map) +// Which functions in previous parts can you rewrite to use `map` instead? +// (Hint: read the source code of `map`, and see if the pattern appears in your own code.) +// Bonus: [`test_invariant` in Part 05](part05.html#section-6) doesn't use `match`, +// but can you still find a way to rewrite it with `map`? + //@ [index](main.html) | [previous](part09.html) | [raw source](workspace/src/part10.rs) | //@ [next](part11.html) diff --git a/src/part12.rs b/src/part12.rs index e7ccf99..276ccaf 100644 --- a/src/part12.rs +++ b/src/part12.rs @@ -12,7 +12,7 @@ use std::cell::{Cell, RefCell}; //@ ## `Rc` //@ The solution is to find some way of cloning `Callbacks` without cloning the environments. This -//@ can be achieved with `Rc<T>`, a *reference-counted* pointer. This is is another example of a +//@ can be achieved with `Rc<T>`, a *reference-counted* pointer. This is another example of a //@ smart pointer. You can `clone` an `Rc` as often as you want, that doesn't affect the data it //@ contains. It only creates more references to the same data. Once all the references are gone, //@ the data is deleted. diff --git a/src/part13.rs b/src/part13.rs index 31f629b..ac7698c 100644 --- a/src/part13.rs +++ b/src/part13.rs @@ -198,7 +198,7 @@ pub fn main() { //@ functions provided by `Send`. What the trait says is that types which are `Send` can be safely //@ sent to another thread without causing trouble. //@ Of course, all the primitive data-types are `Send`. So is `Arc`, which is why Rust accepted our -//@ code. But `Rc` is not `Send`, and for a good reason! If had two `Rc` to the same data, and sent +//@ code. But `Rc` is not `Send`, and for a good reason! If we had two `Rc`s to the same data, and sent //@ one of them to another thread, things could go havoc due to the lack of synchronization. //@ //@ Now, `Send` as a trait is fairly special. It has a so-called *default implementation*. This diff --git a/src/part15.rs b/src/part15.rs index e646d34..e22d507 100644 --- a/src/part15.rs +++ b/src/part15.rs @@ -28,7 +28,7 @@ use std::time::Duration; //@ Rather than giving every field a name, a struct can also be defined by just giving a sequence //@ of types (similar to how a variant of an `enum` is defined). This is called a *tuple struct*. //@ It is often used when constructing a *newtype*, as we do here: `ConcurrentCounter` is -//@ essentially just a new name for `Arc<Mutex<usize>>`. However, is is a locally declared types, +//@ essentially just a new name for `Arc<Mutex<usize>>`. However, it is a locally declared types, //@ so we can give it an inherent implementation and implement traits for it. Since the field is //@ private, nobody outside this module can even know the type we are wrapping. diff --git a/workspace/Cargo.lock b/workspace/Cargo.lock index 7111b99..3040431 100644 --- a/workspace/Cargo.lock +++ b/workspace/Cargo.lock @@ -1,4 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + [[package]] name = "rust-101-workspace" version = "0.0.0" -