# Command-Line Rust ![rw-book-cover](https://m.media-amazon.com/images/I/81owICX8ihL._SY160.jpg) ## Metadata - Author: Ken Youens-Clark - Full Title: Command-Line Rust - Category: #cli-tools #rust ## Highlights - Rust uses a struct (structure) to represent complex data types and traits to describe how types can behave. ([Location 63](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=63)) - Functions are also first-class values, which means they can be passed as arguments to other so-called higher-order functions. ([Location 68](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=68)) - Most exciting to my mind is Rust’s use of enumerated and sum types, also called algebraic data types (ADTs), which allow you to represent, for instance, that a function can return a Result that can be either an Ok containing some value or an Err containing some other kind of value. ([Location 69](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=69)) - Linting is automatically checking code for common mistakes, and it seems most languages offer one or more linters. ([Location 167](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=167)) - “More than the act of testing, the act of designing tests is one of the best bug preventers known. The thinking that must be done to create a useful test can discover and eliminate bugs before they are coded—indeed, test-design thinking can discover and eliminate bugs at every stage in the creation of software, from conception to specification, to design, coding, and the rest.” Boris Beizer, Software Testing Techniques (Van Nostrand Reinhold) ([Location 432](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=432)) - Inside-out or unit testing is when you write tests for the functions inside your program. I’ll introduce unit testing in Chapter 5. Outside-in or integration testing is when you write tests that run your programs as the user might, and that’s what we’ll do for this program. ([Location 440](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=440)) - I want to test the program that lives in the current crate. I can use the crate assert_cmd to find the program in my crate directory. I will also add the crate pretty_assertions to use a version of the assert_eq! macro that shows differences between two strings better than the default version. ([Location 582](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=582)) - I can then use assert_cmd to create a Command that looks in the Cargo binary directories. ([Location 603](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=603)) - Command-line programs should report a final exit status to the operating system to indicate success or failure. ([Location 640](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=640)) - All the programs you will write in this book will be expected to return zero when they terminate normally and a nonzero value when there is an error. ([Location 659](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=659)) - The tests are not necessarily run in the same order they are declared in the code. This is because Rust is a safe language for writing concurrent code, which means code can be run across multiple threads. The testing takes advantage of this concurrency to run many tests in parallel, so the test results may appear in a different order each time you run them. This is a feature, not a bug. If you would like to run the tests in order, you can run them on a single thread via cargo test -- --test-threads=1. ([Location 692](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=692)) - The unit type is like an empty value and is signified with a set of empty parentheses: (). The documentation says this “is used when there is no other meaningful value that could be returned.” ([Location 953](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=953)) - struct, which is a kind of data structure in Rust. ([Location 971](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=971)) - A trait in Rust is a way to define the behavior of an object in an abstract way. ([Location 1006](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1006)) - If you are unfamiliar with command-line arguments, it’s common for the first value to be the path of the program itself. ([Location 1023](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1023)) - That doesn’t work because Cargo thinks the -n argument is for itself, not the program I’m running. To fix this, I need to separate Cargo’s options using two dashes: $ cargo run -- -n Hello world ([Location 1034](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1034)) - Typically, program options start with one or two dashes. It’s common to have short names with one dash and a single character, like -h for the help flag, and long names with two dashes and a word, like --help. ([Location 1039](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1039)) - Cargo places the downloaded source code into .cargo in your home directory, and the build artifacts go into the target​/⁠debug/deps directory of the project. ([Location 1076](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1076)) - Next, I need to define the parameters using the clap::Arg struct and clap::ArgAction enum, which is an enumeration of possible values. ([Location 1141](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1141)) - When you use println!, the output appears on STDOUT, but the usage and error messages are all appearing on STDERR, which you first saw in Chapter 1. To see this in the bash shell, you can run echor and redirect channel 1 (STDOUT) to a file called out and channel 2 (STDERR) to a file called err: ([Location 1240](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1240)) - So you see that another hallmark of well-behaved command-line programs is to print regular output to STDOUT and error messages to STDERR. ([Location 1252](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1252)) - This call may or may not succeed, so the return value is represented using an Option, which has the variants None for no value and Some for an existing value. ([Location 1267](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1267)) - If you call Option::unwrap on a None, it will cause a panic that will crash your program. You should only call unwrap if you are positive the value is the Some variant. ([Location 1288](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1288)) - In both instances, Rust is duplicating the data, but the type of the data determines whether it is copied or cloned—operations that are tied to the kind of memory that Rust uses. ([Location 1295](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1295)) - First there is the stack, where items of known sizes are accessed in last-in, first-out (LIFO) order. ([Location 1301](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1301)) - Because the items on the stack have a fixed size, Rust can set aside a particular chunk of memory and find it quickly. ([Location 1303](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1303)) - Data types like integers that live on the stack can be easily replicated via an action called copy. ([Location 1304](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1304)) - The other type of memory is the heap, where the sizes of the values may change over time. ([Location 1305](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1305)) - To find the memory where the data lives, Rust stores the memory address on the stack. This is called a pointer because it points to the actual data, and so is also said to be a reference to the data. Items that live on the heap may be very large, so copying the data requires you to acknowledge this difference via the action called clone. ([Location 1312](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1312)) - The values in Rust vectors must all be of the same type. Dynamic languages often allow lists to mix types like strings and numbers, but Rust will complain about “mismatched types.” ([Location 1337](https://readwise.io/to_kindle?action=open&asin=B09QFQ3Y64&location=1337))