I'm writing a function that requires the individual digits of a larger integer to perform operations on.
I've tried the following:
fn example(num: i32) {
// I can safely unwrap because I know the chars of the string are going to be valid
let digits = num.to_string().chars().map(|d| d.to_digit(10).unwrap());
for digit in digits {
println!("{}", digit)
}
}
But the borrow checker says the string doesn't live long enough:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:3:18
|
3 | let digits = num.to_string().chars().map(|d| d.to_digit(10).unwrap());
| ^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
4 | for digit in digits {
| ------ borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
The following does work:
let temp = num.to_string();
let digits = temp.chars().map(|d| d.to_digit(10).unwrap());
But that looks even more contrived.
Is there a better, and possibly more natural way of doing this?
But the borrow checker says the string doesn't live long enough.
That's because it doesn't. You aren't using the iterator, so the type of digits is
std::iter::Map<std::str::Chars<'_>, <closure>>
That is, a yet-to-be-evaluated iterator that contains references to the allocated string (the unnamed lifetime '_ in Chars). However, since that string has no owner, it is dropped at the end of the statement; before the iterator is consumed.
So, yay for Rust, it prevented a use-after-free bug!
Consuming the iterator would "solve" the problem, as the references to the allocated string would not attempt to live longer than the allocated string; they all end at the end of the statement:
let digits: Vec<_> = num.to_string().chars().map(|d| d.to_digit(10).unwrap()).collect();
If you wanted to return an iterator, you can then convert the Vec back into an iterator:
fn digits(num: usize) -> impl Iterator<Item = u32> {
num.to_string()
.chars()
.map(|d| d.to_digit(10).unwrap())
.collect::<Vec<_>>()
.into_iter()
}
As for an alternate solution, there's the math way, stolen from the C++ question to create a vector:
fn x(n: usize) -> Vec<usize> {
fn x_inner(n: usize, xs: &mut Vec<usize>) {
if n >= 10 {
x_inner(n / 10, xs);
}
xs.push(n % 10);
}
let mut xs = Vec::new();
x_inner(n, &mut xs);
xs
}
fn main() {
let num = 42;
let digits: Vec<_> = num.to_string().chars().map(|d| d.to_digit(10).unwrap()).collect();
println!("{:?}", digits);
let digits = x(42);
println!("{:?}", digits);
}
However, you might want to add all the special case logic for negative numbers, and testing wouldn't be a bad idea.
You might also want a fancy-pants iterator version:
fn digits(mut num: usize) -> impl Iterator<Item = usize> {
let mut divisor = 1;
while num >= divisor * 10 {
divisor *= 10;
}
std::iter::from_fn(move || {
if divisor == 0 {
None
} else {
let v = num / divisor;
num %= divisor;
divisor /= 10;
Some(v)
}
})
}
Or the completely custom type:
struct Digits {
n: usize,
divisor: usize,
}
impl Digits {
fn new(n: usize) -> Self {
let mut divisor = 1;
while n >= divisor * 10 {
divisor *= 10;
}
Digits {
n: n,
divisor: divisor,
}
}
}
impl Iterator for Digits {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
if self.divisor == 0 {
None
} else {
let v = Some(self.n / self.divisor);
self.n %= self.divisor;
self.divisor /= 10;
v
}
}
}
fn main() {
let digits: Vec<_> = Digits::new(42).collect();
println!("{:?}", digits);
}
See also:
What is the correct way to return an Iterator (or any other trait)?
Related
I have this code, for learning purposes:
struct Fibonacci {
curr: u32,
next: u32,
}
impl Iterator for Fibonacci {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
let current = self.curr;
self.curr = self.next;
self.next = current + self.next;
Some(current)
}
}
impl Fibonacci {
fn new() -> Self {
Fibonacci { curr: 0, next: 1 }
}
fn current(&self) -> u32 {
self.curr
}
}
fn main() {
println!("The first four terms of the Fibonacci sequence are: ");
let fib = Fibonacci::new();
for i in fib.take(4) {
println!("> {}", i);
}
// println!("cur {}", fib.current()); // *fails*
}
Here fib.take(4) consumes the fib value, so the commented out println below the loop doing fib.current() fails , quite naturally, with:
let fib = Fibonacci::new();
--- move occurs because `fib` has type `Fibonacci`, which does not implement the `Copy` trait
for i in fib.take(4) {
------- `fib` moved due to this method call
...
println!("cur {}", fib.current());
^^^^^^^^^^^^^ value borrowed here after move
note: this function takes ownership of the receiver `self`, which moves `fib`
How would I implement the code above such that the Iterator does not consume it's value, and I can use the fib variable after the loop ?
You can use .by_ref():
Borrows an iterator, rather than consuming it.
This is useful to allow applying iterator adapters while still retaining ownership of the original iterator.
println!("The first four terms of the Fibonacci sequence are: ");
let mut fib = Fibonacci::new();
for i in fib.by_ref().take(4) {
println!("> {}", i);
}
println!("cur {}", fib.current());
The first four terms of the Fibonacci sequence are:
> 0
> 1
> 1
> 2
cur 3
I can't figure out how to get the following to work. I think I need the closure to borrow by &mut Vec, but I don't know how to express that. This is distilled from a larger function, but shows the same error.
fn main() {
let mut v = vec![0; 10];
let next = |i| (i + 1) % v.len();
v[next(1usize)] = 1;
v.push(13);
v[next(2usize)] = 1;
}
Error:
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
--> a.rs:9:5
|
5 | let next = |i| {
| --- immutable borrow occurs here
6 | (i + 1) % v.len()
| - first borrow occurs due to use of `v` in closure
...
9 | v[next(1usize)] = 1;
| ^ ---- immutable borrow later used here
| |
| mutable borrow occurs here
error: aborting due to previous error
If you really want to do it with a closure, you will have to pass the vector by parameter:
let next = |v: &Vec<_>, i| (i + 1) % v.len();
This makes the closure borrow per-call, rather than capture for the scope. You still need to separate the borrows, though:
let j = next(&v, 1usize);
v[j] = 1;
To make your life easier, you can put everything inside the closure instead:
let next = |v: &mut Vec<_>, i, x| {
let j = (i + 1) % v.len();
v[j] = x;
};
Which allows you to simply do:
next(&mut v, 1usize, 1);
next(&mut v, 2usize, 2);
// etc.
This pattern is useful for cases where you are writing a closure just for avoiding local code repetition (which I suspect is why you are asking given the comments).
Since the closure only needs the length of the Vec. Then instead, you can just get that prior to the closure. Then you avoid the whole borrowing issue, as the closure doesn't need to borrow v anymore.
fn main() {
let mut v = vec![0; 10];
let len = v.len();
let next = |i| (i + 1) % len;
v[next(1usize)] = 1;
}
Assuming your closure is not dependent on other things, then instead of a closure, you could define a trait with a method that does that.
For simplicity let's call the trait VecExt and the method set.
trait VecExt<T> {
fn set(&mut self, index: usize, value: T);
}
impl<T> VecExt<T> for Vec<T> {
fn set(&mut self, index: usize, value: T) {
let len = self.len();
self[(index + 1) % len] = value;
}
}
fn main() {
let mut v = vec![0; 10];
v.set(1, 1);
v.push(13);
v.set(2, 1);
}
A closure probably isn't the right tool for the job. The compiler is unhappy because your closure has taken a reference against your Vec, but then while that closure reference is still outstanding you're trying to mutate the Vec. Under Rust's borrow rules, that's not allowed.
The most straightforward approach would be storing your data inside a struct, and making next a member function. That way, there's no closure taking references; it can just check the length only when needed.
struct WrapVec<T>(Vec<T>);
impl<T> WrapVec<T> {
fn wrap_next(&mut self, index: usize) -> &mut T {
let index = (index + 1) % self.0.len();
&mut self.0[index]
}
}
fn main() {
let mut v = WrapVec(vec![0; 10]);
*v.wrap_next(1) = 1;
v.0.push(13);
*v.wrap_next(2) = 1;
}
If you want to be able to apply this function to any Vec, then you may find it useful to define a new trait. For example:
trait WrapNext<T> {
fn wrap_next(&mut self, index: usize) -> &mut T;
}
impl<T> WrapNext<T> for Vec<T> {
fn wrap_next(&mut self, index: usize) -> &mut T {
let index = (index + 1) % self.len();
&mut self[index]
}
}
fn main() {
let mut v = vec![0; 10];
*v.wrap_next(1) = 1;
v.push(13);
*v.wrap_next(2) = 1;
}
In addition to the other answers here, you can use a macro to scope v so you don't have to pass it in every call:
fn main() {
let mut v = vec![0; 10];
macro_rules! next {
// rule to get an index
($i: expr) => {
($i + 1) % v.len()
};
// rule to mutate the vector
($i: expr => $v: expr) => {{
let ind = next!($i);
v[ind] = $v;
}};
};
// get an index
let ind = next!(1usize);
// mutate the vector
v[ind] = 1;
v.push(13);
// or, with the mutation syntax
next!(2usize => 3);
println!("{:?}", v);
}
Why does this code compile?
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let x = "eee";
let &m;
{
let y = "tttt";
m = longest(&x, &y);
}
println!("ahahah: {}", m);
}
For me, there should be a compilation error because of lifetimes.
If I write the same code with i64, I get an error.
fn ooo<'a>(x: &'a i64, y: &'a i64) -> &'a i64 {
if x > y {
x
} else {
y
}
}
fn main() {
let x = 3;
let &m;
{
let y = 5;
m = ooo(&x, &y);
}
println!("ahahah: {}", m);
}
The error is:
error[E0597]: `y` does not live long enough
--> src/main.rs:103:25
|
103 | m = ooo(&x, &y);
| ^^ borrowed value does not live long enough
104 | }
| - `y` dropped here while still borrowed
105 | println!("ahahah: {}", m);
| - borrow later used here
There are a few things we need to know to understand this. The first is what the type of a string literal is. Any string literal (like "foo") has the type &'static str. This is a reference to a string slice, but moreover, it's a static reference. This kind of reference lasts for the entire length of the program and can be coerced to any other lifetime as needed.
This means that in your first piece of code, x and y are already both references and have type &'static str. The reason the call longest(&x, &y) still works (even though &x and &y have type &&'static str) is due to Deref coercion. longest(&x, &y) is really de-sugared as longest(&*x, &*y) to make the types match.
Let's analyze the lifetimes in the first piece of code.
fn main() {
// x: &'static str
let x = "eee";
// Using let patterns in a forward declaration doesn't really make sense
// It's used for things like
// let (x, y) = fn_that_returns_tuple();
// or
// let &x = fn_that_returns_reference();
// Here, it's the same as just `let m;`.
let &m;
{
// y: &'static str
let y = "tttt";
// This is the same as `longest(x, y)` due to autoderef
// m: &'static str
m = longest(&x, &y);
}
// `m: &static str`, so it's still valid here
println!("ahahah: {}", m);
}
(playground)
With the let &m; you may have meant something like let m: &str to force its type. This I think actually would ensure that the lifetime of the reference in m starts with that forward declaration. But since m has type &'static str anyway, it doesn't matter.
Now let's look at the second version with i64.
fn main() {
// x: i64
// This is a local variable
// and will be dropped at the end of `main`.
let x = 3;
// Again, this doesn't really make sense.
let &m;
// If we change it to `let m: &i64`, the error changes,
// which I'll discuss below.
{
// Call the lifetime roughly corresponding to this block `'block`.
// y: i64
// This is a local variable,
// and will be dropped at the end of the block.
let y = 5;
// Since `y` is local, the lifetime of the reference here
// can't be longer than this block.
// &y: &'block i64
// m: &'block i64
m = ooo(&x, &y);
} // Now the lifetime `'block` is over.
// So `m` has a lifetime that's over
// so we get an error here.
println!("ahahah: {}", m);
}
(playground)
If we change the declaration of m to let m: &i64 (which is what I think you meant), the error changes.
error[E0597]: `y` does not live long enough
--> src/main.rs:26:21
|
26 | m = ooo(&x, &y);
| ^^ borrowed value does not live long enough
27 | } // Now the lifetime `'block` is over.
| - `y` dropped here while still borrowed
...
30 | println!("ahahah: {}", m);
| - borrow later used here
(playground)
So now we explicitly want m to last as long as the outer block, but we can't make y last that long, so the error happens at the call to ooo.
Since both these programs are dealing with literals, we actually can make the second version compile. To do this, we have to take advantage of static promotion. A good summary of what that means can be found at the Rust 1.21 announcement (which was the release the introduced this) or at this question.
In short, if we directly take a reference to a literal value, that reference may be promoted to a static reference. That is, it's no longer referencing a local variable.
fn ooo<'a>(x: &'a i64, y: &'a i64) -> &'a i64 {
if x > y {
x
} else {
y
}
}
fn main() {
// due to promotion
// x: &'static i64
let x = &3;
let m;
{
// due to promotion
// y: &'static i64
let y = &5;
// m: &'static i64
m = ooo(x, y);
}
// So `m`'s lifetime is still active
println!("ahahah: {}", m);
}
(playground)
Your examples are not exactly the same. A string literal, "eee" has type &str, not str, so the corresponding code with integers looks like this:
fn ooo<'a>(x: &'a i64, y: &'a i64) -> &'a i64 {
if x > y {
x
} else {
y
}
}
fn main() {
let x = &3;
let &m;
{
let y = &5;
m = ooo(&x, &y);
}
println!("ahahah: {}", m);
}
And it compiles.
The reason that this (and the &str example) works is because local inline literal references are given the 'static lifetime. That is, they are placed in the static data portion of the final binary and are available in memory for the full lifespan of the program.
Such as:
let mut a : usize = 0xFF;
a += -1; // -1 may be from other variable, so there can't be a -= 1;
println!("{}", a);
The output is:
error[E0277]: the trait bound `usize: std::ops::Neg` is not satisfied
anyway?
Your attempt does not work because in Rust, you can only do operations between strictly similar types. Rust does not do any implicit numeric cast because it would be a shoot in the foot as you can see below: you have a special case and several ways to have an overflow.
One way to go is to cast the absolute value of the i32 to usize and add or remove it according to whether it is negative or positive. However, you must handle the special case of the minimal value that overflows when you take its absolute value:
fn add(u: usize, i: i32) -> usize {
if i.is_negative() {
u - i.wrapping_abs() as u32 as usize
} else {
u + i as usize
}
}
fn main() {
let u = 7;
let i1 = -1;
let i2 = 1;
let min = -2_147_483_648;
assert_eq!(add(u, i1), 6);
assert_eq!(add(u, i2), 8);
assert_eq!(add(3_000_000_000, min), 852_516_352);
}
You may also verify the overflows:
fn add(u: usize, i: i32) -> Option<usize> {
if i.is_negative() {
u.checked_sub(i.wrapping_abs() as u32 as usize)
} else {
u.checked_add(i as usize)
}
}
fn main() {
let u = 7;
let i1 = -1;
let i2 = 1;
assert_eq!(add(u, i1), Some(6));
assert_eq!(add(u, i2), Some(8));
assert_eq!(add(0, -1), None);
}
I want to implement a Fibonacci series along with caching the already calculated results. I'm not sure this approach is even possible in Rust, but its the best I've come up with. Here's the code:
use std::collections::HashMap;
pub fn fib_hash(n: u32) -> u64 {
let mut map: HashMap<u32, u64> = HashMap::new();
// This is the engine which recurses saving each value in the map
fn f(map: &HashMap<u32, u64>, n: u32) -> u64 {
let c = match map.get(&n) {
Some(&number) => number,
_ => 0,
};
if c != 0 {
return c;
}
let m = match n {
1 if n < 1 => 0,
1...2 => 1,
_ => f(&map, n - 1) + f(&map, n - 2),
};
map.insert(n, m);
m
}
f(&map, n)
}
The idea is to have a "global" HashMap which can be reused. However, I'm guessing this is not really possible since we'll end up having multiple mutable borrowers for the map. This is the error I get
Rust 2015
error[E0596]: cannot borrow immutable borrowed content `*map` as mutable
--> src/lib.rs:20:9
|
7 | fn f(map: &HashMap<u32, u64>, n: u32) -> u64 {
| ------------------ use `&mut HashMap<u32, u64>` here to make mutable
...
20 | map.insert(n, m);
| ^^^ cannot borrow as mutable
Rust 2018
error[E0596]: cannot borrow `*map` as mutable, as it is behind a `&` reference
--> src/lib.rs:20:9
|
7 | fn f(map: &HashMap<u32, u64>, n: u32) -> u64 {
| ------------------ help: consider changing this to be a mutable reference: `&mut std::collections::HashMap<u32, u64>`
...
20 | map.insert(n, m);
| ^^^ `map` is a `&` reference, so the data it refers to cannot be borrowed as mutable
Can I use this approach in Rust? What would be the best solution to this problem?
You declared the map argument to f as &HashMap<u32, u64>, which is an immutable reference that only allows you to call get and other functions that do not modify the HashMap. Use &mut HashMap<u32, u64> as the type of map to require a reference that allows mutation. This also requires you to annotate the call site with &mut map instead of &map.
Personally I'd use a different approach using ownership transfer instead of references. But everyone has their own style.
pub fn fib_hash(n: u32) -> u64 {
// This is the engine which recurses saving each value in the map
fn f(map: HashMap<u32, u64>, n: u32) -> (HashMap<u32, u64>, u64) {
if let Some(&number) = map.get(&n) {
return (map, number);
}
let (map, a) = f(map, n - 1);
let (mut map, b) = f(map, n - 2);
let res = a + b;
map.insert(n, res);
(map, res)
}
let mut map = HashMap::new();
map.insert(0, 0);
map.insert(1, 1);
map.insert(2, 1);
f(map, n).1
}
Playground
The trick is making map a mutable reference in the parameter list (and using lifetimes explicitly):
use std::collections::HashMap;
fn fib<'a>(n: u32, memo: &'a mut HashMap<u32, u32>) -> u32 {
if n <= 2 {
return 1;
}
return match memo.get(&n) {
Some(&sum) => sum,
None => {
let new_fib_sum = fib(n - 1, memo) + fib(n - 2, memo);
memo.insert(n, new_fib_sum);
new_fib_sum
}
};
}
fn main() {
let mut memo: HashMap<u32, u32> = HashMap::new();
let n = 10; //or user input...or whatever
print!("{}", fib(n, &mut memo));
}