This question already has answers here:
How do I update a variable in a loop to a reference to a value created inside the loop?
(2 answers)
How to abstract over a reference to a value or a value itself?
(1 answer)
Is it possible to return either a borrowed or owned type in Rust?
(1 answer)
Closed 5 years ago.
I'm trying to learn Rust by translating C++ code from the "Elements of Programming" book by Stepanov and McJones. Here's a simple code snippet:
extern crate num_bigint;
use num_bigint::BigInt;
pub fn fibonacci_matrix_multiply(x: (&BigInt, &BigInt), y: (&BigInt, &BigInt)) -> (BigInt, BigInt) {
(x.0 * (y.1 + y.0) + x.1 * y.0, x.0 * y.0 + x.1 * y.1)
}
pub fn power_accumulate_positive(
mut r: (&BigInt, &BigInt),
mut a: (&BigInt, &BigInt),
mut n: i32,
) -> (BigInt, BigInt) {
loop {
if n & 1 == 1 {
r = fibonacci_matrix_multiply(r, a);
if n == 1 {
return r;
}
}
a = fibonacci_matrix_multiply(a, a);
n = n / 2;
}
}
fn main() {}
Here's the error messages:
error[E0308]: mismatched types
--> src/main.rs:16:17
|
16 | r = fibonacci_matrix_multiply(r, a);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found struct `num_bigint::BigInt`
|
= note: expected type `(&num_bigint::BigInt, &num_bigint::BigInt)`
found type `(num_bigint::BigInt, num_bigint::BigInt)`
error[E0308]: mismatched types
--> src/main.rs:18:24
|
18 | return r;
| ^ expected struct `num_bigint::BigInt`, found reference
|
= note: expected type `(num_bigint::BigInt, num_bigint::BigInt)`
found type `(&num_bigint::BigInt, &num_bigint::BigInt)`
error[E0308]: mismatched types
--> src/main.rs:21:13
|
21 | a = fibonacci_matrix_multiply(a, a);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected reference, found struct `num_bigint::BigInt`
|
= note: expected type `(&num_bigint::BigInt, &num_bigint::BigInt)`
found type `(num_bigint::BigInt, num_bigint::BigInt)`
I understand that I'm returning a tuple of structs and trying to assign it to a tuple of references, but I don't know how to solve the problem.
Is there a reason you can't take the BigInts by value instead of by reference? This would remove all the borrow checker errors. Unless it's a clear and measured bottleneck to clone the BigInts, passing by reference won't be much faster and it's less ergonomic.
Here's a working solution that doesn't use references (and instead clones the values)
extern crate num_bigint;
use num_bigint::BigInt;
pub fn fibonacci_matrix_multiply(x: (BigInt, BigInt), y: (BigInt, BigInt)) -> (BigInt, BigInt) {
(&x.0 * (&y.1 + &y.0) + &x.1 * &y.0, x.0 * y.0 + x.1 * y.1)
}
pub fn power_accumulate_positive(
mut r: (BigInt, BigInt),
mut a: (BigInt, BigInt),
mut n: i32,
) -> (BigInt, BigInt) {
loop {
if n & 1 == 1 {
r = fibonacci_matrix_multiply(r, a.clone());
if n == 1 {
return r;
}
}
a = fibonacci_matrix_multiply(a.clone(), a);
n = n / 2;
}
}
Related
I'm running through some LeetCode challenges to build up my understanding of Rust. I'm trying to write the following program that takes an i32 input, converts it to a String, reverses the digits, and returns back an i32 number.
In the case of negative numbers, e.g. -132, when the number is reversed the hyphen has to be popped off the stack: -132 -> 231- -> 231.
I've written the following code but I'm bumping up against the borrow checker, can anyone help?
impl Solution {
pub fn reverse(x: i32) -> i32 {
if(x == 0){
return x;
}
let reversed : std::iter::Rev<std::str::Chars> = x.to_string().chars().rev();
if reversed.last().unwrap() == '-' { //error occurs here
return reversed.collect::<String>()[0..reversed.count()].parse::<i32>().unwrap();
} else {
return reversed.collect::<String>().parse::<i32>().unwrap();
}
}
}
Line 6, Char 61: temporary value dropped while borrowed (solution.rs)
|
6 | let reversed : &std::iter::Rev<std::str::Chars> = &x.to_string().chars().rev();
| ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
7 | if reversed.last().unwrap() == '-' {
| -------- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
Line 7, Char 12: cannot move out of `*reversed` which is behind a shared reference (solution.rs)
|
7 | if reversed.last().unwrap() == '-' {
| ^^^^^^^^ move occurs because `*reversed` has type `std::iter::Rev<std::str::Chars<'_>>`, which does not implement the `Copy` trait
Line 8, Char 20: cannot move out of `*reversed` which is behind a shared reference (solution.rs)
|
8 | return reversed.collect::<String>()[0..reversed.count()].parse::<i32>().unwrap();
| ^^^^^^^^ move occurs because `*reversed` has type `std::iter::Rev<std::str::Chars<'_>>`, which does not implement the `Copy` trait
Line 8, Char 52: cannot move out of `*reversed` which is behind a shared reference (solution.rs)
|
8 | return reversed.collect::<String>()[0..reversed.count()].parse::<i32>().unwrap();
| ^^^^^^^^ move occurs because `*reversed` has type `std::iter::Rev<std::str::Chars<'_>>`, which does not implement the `Copy` trait
Line 10, Char 20: cannot move out of `*reversed` which is behind a shared reference (solution.rs)
|
10 | return reversed.collect::<String>().parse::<i32>().unwrap();
| ^^^^^^^^ move occurs because `*reversed` has type `std::iter::Rev<std::str::Chars<'_>>`, which does not implement the `Copy` trait
Here's the error reproduced in a playground
Original error reproduced in this playground
Here's a solution that is close to your approach that fixes the error:
fn reverse(x: i32) -> i32 {
if x == 0 {
return x;
}
let mut reversed:String = x.to_string().chars().rev().collect::<String>();
if reversed.chars().last() == Some('-') {
reversed.pop();
}
reversed.parse::<i32>().unwrap()
}
working version: playground
This other post has good explanation of why. In the context of this question:
x.to_string().chars().rev();
// ^ ^
// String <- &str
to_string returns a String, but the code has no reference to that String after this statement, so it needs to free the String, but the iterator refers to the &str from chars() which then becomes a reference to something that no longer exists. By changing the type of reversed to String and using collect then Rust can bind the new data to the local variable and doesn't have to drop it at the end of the statement.
Does the LeetCode challenge impose the int→string→int conversions? I would do it directly on ints:
fn reverse (x: i32) -> i32 {
let mut x = x.abs();
let mut y = 0;
while x != 0 {
y = y*10 + x%10;
x = x/10;
}
return y;
}
Why not just take the absolute value of x before converting it to a String so you don't have to deal with the hyphen edge case?
fn reverse(x: i32) -> i32 {
x.abs()
.to_string()
.chars()
.rev()
.collect::<String>()
.parse::<i32>()
.unwrap()
}
fn main() {
assert_eq!(reverse(1234567), 7654321);
assert_eq!(reverse(-1234567), 7654321);
}
playground
Even if we get the input as a String and have to deal with the hyphen the most idiomatic solution would be to filter() it out:
fn reverse(x: String) -> i32 {
x.chars()
.filter(|&c| c != '-')
.rev()
.collect::<String>()
.parse::<i32>()
.unwrap()
}
fn main() {
assert_eq!(reverse(1234567.to_string()), 7654321);
assert_eq!(reverse((-1234567).to_string()), 7654321);
}
playground
I am trying to use ndarray to calculate dot products, and am getting compilation errors that I don't understand.
My basic function is
use ndarray::{ArrayD, ArrayBase};
pub fn cosine<L>(v1: &ArrayBase<f64, L>, v2: &ArrayBase<f64, L>) -> f64 {
let x: f64 = v1.dot(&v2) / (v1.dot(v1) * v2.dot(v2)).sqrt();
return x
}
pub fn cosine2(v1: &ArrayD<f64>, v2: &ArrayD<f64>) -> f64 {
let x: f64 = v1.dot(v2) / (v1.dot(v1) * v2.dot(v2)).sqrt();
return x
}
which fails to compile:
error[E0277]: the trait bound `f64: ndarray::data_traits::RawData` is not satisfiedchgraph
--> src/simple.rs:3:1
|
3 | / pub fn cosine<L>(v1: &ArrayBase<f64, L>, v2: &ArrayBase<f64, L>) -> f64 {
4 | | let x: f64 = v1.dot(&v2) / (v1.dot(v1) * v2.dot(v2)).sqrt();
5 | | }
| |_^ the trait `ndarray::data_traits::RawData` is not implemented for `f64`
|
= note: required by `ndarray::ArrayBase`
If I comment out cosine, I get an error from cosine2:
error[E0599]: no method named `dot` found for reference `&ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<f64>, ndarray::dimension::dim::Dim<ndarray::dimension::dynindeximpl::IxDynImpl>>` in the current scope
--> src/simple.rs:9:21
|
9 | let x: f64 = v1.dot(v2) / (v1.dot(v1) * v2.dot(v2)).sqrt();
| ^^^ method not found in `&ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<f64>, ndarray::dimension::dim::Dim<ndarray::dimension::dynindeximpl::IxDynImpl>>`
(and two more copies for the other dot products). Why can the second version not find the method? It seems that ArrayD is a type based on Array, which is in turn a type based on ArrayBase, so ArrayD::dot should be an existing method.
I only need to be able to pass an ArrayD, so I am happy with a version of either that works.
The relevant parts of my Cargo.toml are
[dependencies.ndarray]
version = "0.13.1"
[features]
default = ["ndarray/blas"]
First of all, the data type of ArrayBase is not indexed by the data type, but a RawData wrapper of the data type. Second of all, dot requires the Dot trait to be implemented. So, you should add these both to the trait bounds:
use ndarray::linalg::Dot;
use ndarray::{ArrayBase, ArrayD, RawData};
pub fn cosine<D, L>(v1: &ArrayBase<D, L>, v2: &ArrayBase<D, L>) -> f64
where
D: RawData<Elem = f64>,
ArrayBase<D, L>: Dot<ArrayBase<D, L>, Output = f64>,
{
let x: f64 = v1.dot(&v2) / (v1.dot(v1) * v2.dot(v2)).sqrt();
return x;
}
This question already has answers here:
What is the correct way to return an Iterator (or any other trait)?
(2 answers)
"Expected type parameter" error in the constructor of a generic struct
(1 answer)
Closed 2 years ago.
I want make the mapping portion of this line into a function:
let i: Vec<u32> = (0..=5).map(|x| x * 2).collect();
I wrote this code which I assumed would be a drop-in for what I removed from the original code:
let j: Vec<u32> = process(0..=5).collect();
fn process<I>(src: I) -> I
where
I: Iterator<Item = u32>,
{
src.map(|x| x * 2)
}
I get this compile time error:
error[E0308]: mismatched types
--> src/lib.rs:5:5
|
1 | fn process<I>(src: I) -> I
| - - expected `I` because of return type
| |
| this type parameter
...
5 | src.map(|x| x * 2)
| ^^^^^^^^^^^^^^^^^^ expected type parameter `I`, found struct `std::iter::Map`
|
= note: expected type parameter `I`
found struct `std::iter::Map<I, [closure#src/lib.rs:5:13: 5:22]>`
Playground
Since std::iter::Map<u32, u32> implements the Iterator trait, shouldn't it be able to be returned as Iterator<Item = u32>?
I was able to get it working with the following:
fn process<I>(src: I) -> std::iter::Map<I, Box<dyn Fn(u32) -> u32>>
where
I: Iterator<Item = u32>,
{
src.map(Box::new(|x| x * 2))
}
This involves wrapping the closure in a Box. Is there a better or less verbose way to do this that matches the inline function?
I wanted to implement a function computing the number of digits within any generic type of integer. Here is the code I came up with:
extern crate num;
use num::Integer;
fn int_length<T: Integer>(mut x: T) -> u8 {
if x == 0 {
return 1;
}
let mut length = 0u8;
if x < 0 {
length += 1;
x = -x;
}
while x > 0 {
x /= 10;
length += 1;
}
length
}
fn main() {
println!("{}", int_length(45));
println!("{}", int_length(-45));
}
And here is the compiler output
error[E0308]: mismatched types
--> src/main.rs:5:13
|
5 | if x == 0 {
| ^ expected type parameter, found integral variable
|
= note: expected type `T`
found type `{integer}`
error[E0308]: mismatched types
--> src/main.rs:10:12
|
10 | if x < 0 {
| ^ expected type parameter, found integral variable
|
= note: expected type `T`
found type `{integer}`
error: cannot apply unary operator `-` to type `T`
--> src/main.rs:12:13
|
12 | x = -x;
| ^^
error[E0308]: mismatched types
--> src/main.rs:15:15
|
15 | while x > 0 {
| ^ expected type parameter, found integral variable
|
= note: expected type `T`
found type `{integer}`
error[E0368]: binary assignment operation `/=` cannot be applied to type `T`
--> src/main.rs:16:9
|
16 | x /= 10;
| ^ cannot use `/=` on type `T`
I understand that the problem comes from my use of constants within the function, but I don't understand why the trait specification as Integer doesn't solve this.
The documentation for Integer says it implements the PartialOrd, etc. traits with Self (which I assume refers to Integer). By using integer constants which also implement the Integer trait, aren't the operations defined, and shouldn't the compiler compile without errors?
I tried suffixing my constants with i32, but the error message is the same, replacing _ with i32.
Many things are going wrong here:
As Shepmaster says, 0 and 1 cannot be converted to everything implementing Integer. Use Zero::zero and One::one instead.
10 can definitely not be converted to anything implementing Integer, you need to use NumCast for that
a /= b is not sugar for a = a / b but an separate trait that Integer does not require.
-x is an unary operation which is not part of Integer but requires the Neg trait (since it only makes sense for signed types).
Here's an implementation. Note that you need a bound on Neg, to make sure that it results in the same type as T
extern crate num;
use num::{Integer, NumCast};
use std::ops::Neg;
fn int_length<T>(mut x: T) -> u8
where
T: Integer + Neg<Output = T> + NumCast,
{
if x == T::zero() {
return 1;
}
let mut length = 0;
if x < T::zero() {
length += 1;
x = -x;
}
while x > T::zero() {
x = x / NumCast::from(10).unwrap();
length += 1;
}
length
}
fn main() {
println!("{}", int_length(45));
println!("{}", int_length(-45));
}
The problem is that the Integer trait can be implemented by anything. For example, you could choose to implement it on your own struct! There wouldn't be a way to convert the literal 0 or 1 to your struct. I'm too lazy to show an example of implementing it, because there's 10 or so methods. ^_^
num::Zero and num::One
This is why Zero::zero and One::one exist. You can (very annoyingly) create all the other constants from repeated calls to those.
use num::{One, Zero}; // 0.4.0
fn three<T>() -> T
where
T: Zero + One,
{
let mut three = Zero::zero();
for _ in 0..3 {
three = three + One::one();
}
three
}
From and Into
You can also use the From and Into traits to convert to your generic type:
use num::Integer; // 0.4.0
use std::ops::{DivAssign, Neg};
fn int_length<T>(mut x: T) -> u8
where
T: Integer + Neg<Output = T> + DivAssign,
u8: Into<T>,
{
let zero = 0.into();
if x == zero {
return 1;
}
let mut length = 0u8;
if x < zero {
length += 1;
x = -x;
}
while x > zero {
x /= 10.into();
length += 1;
}
length
}
fn main() {
println!("{}", int_length(45));
println!("{}", int_length(-45));
}
See also:
How do I use floating point number literals when using generic types?
What's the proper type annotation in the following code to convert an integer to a float?
use conv::{ValueInto, errors::PosOverflow};
fn run_me() -> Result <f32, PosOverflow<usize>> {
let m: f32 = 21.3;
let n: usize = 23;
let p: f32 = n.value_into()?;
let bar = m * p;
let baz = m * (n.value_into()?); // Compiler error here
Ok(baz)
}
fn main() {
run_me();
}
Which fails with:
error[E0277]: cannot multiply `()` to `f32`
--> src/main.rs:7:17
|
7 | let baz = m * (n.value_into()?);
| ^ no implementation for `f32 * ()`
|
= help: the trait `std::ops::Mul<()>` is not implemented for `f32`
error[E0277]: the trait bound `(): conv::ValueFrom<usize>` is not satisfied
--> src/main.rs:7:22
|
7 | let baz = m * (n.value_into()?);
| ^^^^^^^^^^ the trait `conv::ValueFrom<usize>` is not implemented for `()`
|
= note: required because of the requirements on the impl of `conv::ValueInto<()>` for `usize`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.
error: Could not compile `tmp3`.
To learn more, run the command again with --verbose.
Basically, a conversion from usize to f32 could fail, so we have the conv package to handle the details. In the following code, the bar computes just fine, but baz does not. I'd like a one liner like baz to work directly because more complicated examples will need to chain together multiple conversions.
Edit 1
Ok, so I can force what I want by adding a trait to usize. Is there a problem with this approach or can the original call to value_into be fixed?
use conv::{ValueFrom, ValueInto, errors::PosOverflow};
trait ToF32 {
fn to_f32(self) -> Result<f32, PosOverflow<usize>>;
}
impl ToF32 for usize {
fn to_f32(self) -> Result<f32, PosOverflow<usize>> {
f32::value_from(self)
}
}
fn run_me() -> Result <f32, PosOverflow<usize>> {
let m: f32 = 21.3;
let n: usize = 23;
let p: f32 = n.value_into()?;
let bar = m * p;
let baz = m * n.to_f32()?;
// let buz = m * n.value_into()?;
Ok(baz)
}
fn main() {
run_me();
}
Some functions in Rust like value_into and try_into have to be called when assigning to directly to a typed variable.
To answer your question directly, the proper way to add type annotations is by assigning it into a temporary variable (like you did with bar and p) before using the value.