This section's exercises are meant to be run on your local machine. Make sure you have successfully installed Rust and Cargo on your local machine; ask a helper for assistance if necessary!
Compile and run Hello World locally via rustc
hello.rs
pub fn main() { println!("Hello World"); }
Put the following code into a file named count.rs
.
count.rs
fn count_to(p: &mut u64, mask: u64, max: u64) {
let mut i = *p;
while i < max {
if i & mask != 0 {
*p += 1;
}
i += 1;
}
}
fn main() {
let mut x = 0;
count_to(&mut x, !0, 1 << 25);
println!("x: {}", x);
}
Compile the program with rustc
with no other flags, and then time how long it takes to run. For example, on Unix systems:
$ rustc count.rs
$ time ./count
Now compile the program with optimizations turned on (the -O
flag), and compare how the timing results turn out:
$ rustc -O count.rs
$ time ./count
How much of difference does this make on your platform?
You can investigate differences in the generated code via command-line options:
rustc --emit=asm
will produce assembly for your target platformrustc --emit=llvm-ir
will produce LLVM intermediate representation(Also, you may have noticed that the program is quite a bit more complicated than something that just counts to max
. Feel free to try replacing the i & mask != 0
condition with true
and seeing how the results change.)
Make a new cargo library and run its unit tests:
$ cargo new my_new_library
$ cd my_new_library
$ cargo build
...
$ cargo test
...
Revise your new cargo library so that the unit test prints out "Hello World" via println!
when it runs.
Note: cargo test
captures such output by default, so you will not see it when you run cargo test
with no other options.
You can see options to adjust the latter behavior, that you can pass to the generated tester program, by running cargo test -- --help
.
(Note also that cargo test --help
is quite different from cargo test -- --help
.)
Revise your new cargo library to print out a randomly generated number.
To do this, you should not write your own random number generator; instead, you should grab one off crates.io.
Do a search there for one, and then add the appropriate line to a [dependencies]
section in my_new_library/Cargo.toml
.
This section asks you to write various functions.
To write and test your code, you can either:
Put the code into a cargo library and run cargo test
,
Put the code into a .rs
file, compile it with rustc --test
, and run the resulting binary, or,
Put the code into a .rs
file with a fn main
function and compile + run it the same way you did the earlier "Hello World"-type examples.
(We recommend cargo
.)
Also:
The Vec
API is visible at:
The [T]
(slice) API is visible at:
Write a function:
fn zeroes(count: usize) -> Vec<usize>
that creates a vector of length count
that is filled with 0.
Write a function:
fn histogram(input_data: &[usize]) -> Vec<usize>
that reports, at each index i
of its result vector, the number of times that i
occurs in input_data
.
So for example, these assertions should hold:
assert_eq!(histogram(&[4, 0, 4, 4]),
[1, 0, 0, 0, 3]);
assert_eq!(histogram(&[4, 0, 4, 4, 5, 0, 9, 9, 9, 9, 9]),
[2, 0, 0, 0, 3,
1, 0, 0, 0, 5]);
You may have seen an earlier note that it is not idiomatic in Rust to take an immutably-borrowed &Vec<T>
argument; idiomatic Rust instead uses borrowed slices &[T]
.
Do you think this reasoning applies also to &mut Vec<T>
? That is, for any function that takes &mut Vec<T>
, could we make a replacement function that instead takes &mut [T]
and everything still works out?
If you are not sure of the answer: Go back over the previous section with exercises writing functions that took &mut Vec<i32>
, and write those same functions but now taking &mut [i32]
instead.
To run them, you can either:
Put the code into a cargo library and run cargo test
,
Put the code into a .rs
file, compile it with rustc --test
, and run the resulting binary, or,
Put the code into a .rs
file, replace fn no_longer_main
with fn main
and compile it the same way you did the earlier "Hello World"-type examples.
Also:
The str
API is visible at:
The String
API is visble at:
https://doc.rust-lang.org/stable/std/string/struct.String.html
The exercises in this section concern the code at the following link, which uses unit tests alone for its illustrations:
(You may need to cut-and-paste from the gist link if you choose to use the playpen, due to infrastructural and rate-limit issues.)
You may prefer to put the code on your local machine (either in its own .rs
file, or in a cargo project).
What is being printed out at the end of fn no_longer_main
?
Hint: Running the program is a reasonable way to resolve this question!
Uncomment the lines beneath the one labelled "(*)" above, starting with let borrowed = ...;
Re-run the test suite. Can you explain what you see?
Hint: setting the environment variable RUST_BACKTRACE
to 1 will make Rust programs print out a stack trace when they panic.
So for example, RUST_BACKTRACE=1 cargo test
may provide further information about what is happening.
Write a function
fn listing(input: &[&str]) -> String
that makes a comma-delimited list of all the input strings.
Examples:
["apple", "pear", "banana"] goes to "apple, pear, banana"
An emply slice goes to "".