I want to implement a generic fibonacci function that works with any type implementing Zero, One, and AddAssign. I first implemented a version that works fine, but is specialized for num::BigUint (see on play.rust-lang.org). I than came up with the following generic implementation (see on play.rust-lang.org):
extern crate num;
use num::{One, Zero};
use std::mem::swap;
use std::ops::AddAssign;
fn fib<T: Zero + One + AddAssign<&T>>(n: usize) -> T {
let mut f0 = Zero::zero();
let mut f1 = One::one();
for _ in 0..n {
f0 += &f1;
swap(&mut f0, &mut f1);
}
f0
}
This doesn't compile:
error[E0106]: missing lifetime specifier
--> src/main.rs:7:34
|
7 | fn fib<T: Zero + One + AddAssign<&T>>(n: usize) -> T {
| ^ expected lifetime parameter
Rust wants me to add a lifetime parameter to AddAssign<&T> but I don't know how to express the lifetime of f1.
You need to use Higher Rank Trait Bounds. This one means basically "For any lifetime 'a, T satisfies the AddAssign<&'a T> trait":
fn fib<T>(n: usize) -> T
where
for<'a> T: Zero + One + AddAssign<&'a T>,
I also had to change the way fib is called because the compiler couldn't figure out the return type, which could be literally any type that implements those traits. Declaring x's type gives sufficient context to the compiler so that it knows what you want.
fn main() {
let x: num::BigUint = fib(10);
// let x = fib::<BigUint>(10); // Also works
println!("fib(10) = {}", x);
}
playground
Related
I need the trait XYZ to define a method that allows iterating over some set of integers. This set of integers is defined either by a backing Vec or by a Range<usize>. However, I run into various (lifetime or type) issues depending on how I define the XYZIterator type that is supposed to unify these Iterators over Vec/Range.
The backup solution would be to allocate and return Vecs, but I wondered whether there was a way without cloning/allocating memory.
type XYZIterator = Box<dyn Iterator<Item = usize>>;
trait XYZ {
fn stuff(&self) -> XYZIterator;
}
struct Test {
objects: Vec<usize>,
}
impl XYZ for Test {
fn stuff(&self) -> XYZIterator {
Box::new(self.objects.iter())
}
}
struct Test2 {}
impl XYZ for Test2 {
fn stuff(&self) -> XYZIterator {
Box::new((1..4).into_iter())
}
}
fn main() {
let t1 = Test {
objects: vec![1, 2, 3],
};
let t2 = Test2 {};
t1.stuff().for_each(|x| println!("{}", x));
t2.stuff().for_each(|x| println!("{}", x));
t1.stuff()
.filter(|x| x % 2 == 0)
.for_each(|x| println!("{}", x));
t2.stuff()
.filter(|x| x % 2 == 0)
.for_each(|x| println!("{}", x));
}
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, usize> as Iterator>::Item == usize`
--> src/main.rs:12:9
|
12 | Box::new(self.objects.iter())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `usize`, found reference
|
= note: expected type `usize`
found reference `&usize`
= note: required for the cast to the object type `dyn Iterator<Item = usize>`
Your code has two issues:
In the implementation of XYZ for Test1, you return the iterator self.objects.iter(). Vec::iter iterates over references to the objects, not objects themselves, so this is an iterator over &usize, which doesn't match the return type. You should have gotten an error about this. It's easy to fix though: self.objects.iter().copied() will copy each element out of the reference.
In type XYZIterator = Box<dyn Iterator<Item = usize>>;, since there is no lifetime in the trait object, it defaults to 'static - that is, your iterator can live forever. But that's not the case with the vector iterator - it has a reference to the vector is iterating over. This is where you are having lifetime issues.
The solution is to give the XYZIterator type a lifetime:
type XYZIterator<'a> = Box<dyn Iterator<Item = usize> + 'a>;
And alter the traits and trait implementations to use the lifetime.
Also consider altering your type or function to accept any T: Iterator<Item=usize>; it will then accept any iterator that produces usizes
I'm trying to implement a generic function in Rust where the only requirement for the argument is that the multiplication operation should be defined. I'm trying to implement a generic "power", but will go with a simpler cube function to illustrate the problem:
use std::ops::Mul;
fn cube<T: Mul>(x: T) -> T {
x * x * x
}
fn main() {
println!("5^3 = {}", cube(5));
}
When compiling I get this error:
error[E0369]: binary operation `*` cannot be applied to type `<T as std::ops::Mul>::Output`
--> src/main.rs:4:5
|
4 | x * x * x
| ^^^^^^^^^
|
= note: an implementation of `std::ops::Mul` might be missing for `<T as std::ops::Mul>::Output`
What does this mean? Did I choose the wrong trait? How can I resolve this?
Let's break down your example a bit:
fn cube<T: Mul>(x: T) -> T {
let a = x * x;
let b = a * x;
b
}
What are the types of a and b? In this case, the type of a is <T as std::ops::Mul>::Output — sound familiar from the error message? Then, we are trying to multiply that type by x again, but there's no guarantee that Output is able to be multiplied by anything!
Let's do the simplest thing and say that T * T needs to result in a T:
fn cube<T: Mul<Output = T>>(x: T) -> T {
x * x * x
}
Unfortunately, this gives two similar errors:
error[E0382]: use of moved value: `x`
--> src/lib.rs:6:9
|
6 | x * x * x
| - ^ value used here after move
| |
| value moved here
|
= note: move occurs because `x` has type `T`, which does not implement the `Copy` trait
Which is because the Mul trait takes arguments by value, so we add the Copy so we can duplicate the values.
I also switched to the where clause as I like it better and it is unwieldy to have that much inline:
fn cube<T>(x: T) -> T
where
T: Mul<Output = T> + Copy
{
x * x * x
}
See also:
How do I implement the Add trait for a reference to a struct?
How to write a trait bound for adding two references of a generic type?
The bound T: Mul does not imply that the result of the binary operator is also of type T. The result type is an associated type of this trait: Output.
The other issue is that before Rust 1.0 the operator traits switched from pass-by-reference to pass-by-value. In generic code this can be a bit of a pain in the butt (for now at least) because these operators consume their operands unless you also require the types to be Copy.
Just for completeness (in case you don't like to require Copy), let me add some information about a possible alternative direction.
For the sake of generic code, authors of "numeric types" are encouraged to provide additional non-consuming implementations of these operator traits so that you don't need Copy or Clone. For example, the standard library already provides the following implementations:
f64 implements Mul< f64>
f64 implements Mul<&f64>
&f64 implements Mul< f64>
&f64 implements Mul<&f64>
Each of these implementations has f64 as the Output type. Making use of these traits directly is not pretty:
fn cube<T>(x: &T) -> T
where
for<'a> T: Mul<&'a T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
x * x * x
}
Eventually, we might get some (slightly) higher level traits, which would reduce the noise. For example: T: Mul2 could imply T: Mul<T> + Mul<&T> and &T: Mul<T> + Mul<&T>, but at the time of writing this, the Rust compiler does not seem able to handle this. At least I could not successfully compile the following code:
use std::ops::Mul;
pub trait Mul2
where
Self: Mul<Self, Output = Self>,
Self: for<'a> Mul<&'a Self, Output = Self>,
for<'a> &'a Self: Mul<Self, Output = Self>,
for<'a, 'b> &'a Self: Mul<&'b Self, Output = Self>,
{
}
impl<T> Mul2 for T
where
T: Mul<T, Output = T>,
T: for<'a> Mul<&'a T, Output = T>,
for<'a> &'a T: Mul<T, Output = T>,
for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
}
fn cube<T: Mul2>(x: &T) -> T {
x * x * x
}
fn main() {
let c = cube(&2.3);
println!("Hello, world! {}", c)
}
I think it's safe to say that things will improve in this area. For now, the ability to generically implement numeric algorithms in Rust is not as good as I would like it to be.
I have come across a borrowchecker problem using Rust 2018 that I cannot find the solution to. Basically, I have a function that takes a mutable reference to a vec, and as the first part of its execution passes that same vec into another function as an immutable reference. The latter function returns a new owned value - or at least I intend it to. The problem for me is that the compiler seems to regard the immutable borrow for the function call as lasting until the end of the outer function.
Unfortunately, this isn't a problem that is solved simply by putting braces around things (it shouldn't be anyway since I'm using Rust 2018). Moreover, while I have found a number of SO questions that appear to touch on similar matters (e.g. this, this, this and this), I haven't been able to find anything else that directly addresses this problem. Or at least, nothing where I have been able to work out what I should do from it. Crucially, most other similar questions either seem to involve a reference as the return type or were only an issue before non-lexical lifetimes.
I have created an executable MVE in the Rust Playground, and the full program in case it helps. I post the code below, for reference:
// This function was blatantly borrowed from a Stack Overflow post
// but unfortunately I lost track of which one.
fn compute_mean_of_vec<'g, T>(input_vec: &'g [T]) -> T
where
T: Copy
+ num::Zero
+ std::ops::Add<T, Output = T>
+ std::ops::Div<T, Output = T>
+ num::FromPrimitive
+ std::iter::Sum<&'g T>,
{
let sum: T = input_vec.iter().sum();
sum / num::FromPrimitive::from_usize(input_vec.len()).unwrap()
}
fn normalise_cost_vec<'a, T>(cost_vec: &'a mut Vec<T>)
where
T: std::ops::SubAssign
+ Copy
+ num::traits::identities::Zero
+ std::ops::Div<Output = T>
+ num::traits::cast::FromPrimitive
+ std::iter::Sum<&'a T>,
{
let mean = compute_mean_of_vec(cost_vec);
for c in cost_vec.iter_mut() {
*c -= mean;
}
}
fn main() {
let mut my_vec = vec![5.0f32; 5];
normalise_cost_vec(&mut my_vec);
for e in my_vec.iter() {
println!("{}", e);
}
}
The error message the compiler produces is:
error[E0502]: cannot borrow `*cost_vec` as mutable because it is also borrowed as immutable
--> src/main.rs:26:14
|
16 | fn normalise_cost_vec<'a, T>(cost_vec: &'a mut Vec<T>)
| -- lifetime `'a` defined here
...
25 | let mean = compute_mean_of_vec(cost_vec);
| -----------------------------
| | |
| | immutable borrow occurs here
| argument requires that `*cost_vec` is borrowed for `'a`
26 | for c in cost_vec.iter_mut() {
| ^^^^^^^^ mutable borrow occurs here
Looking at the error message, it looks to me like there is probably some issue with the lifetimes specified on the two functions. I have to admit that the ones I included were pretty much just put there according to the suggestions from the compiler and Clippy, I don't fully understand them. Best as I can tell, the compiler somehow thinks that the immutable borrow in the call to compute_mean_of_vec should last for the entirety of the remainder of the call to normalise_cost_vec.
What have I done wrong, and how can I make the compiler happy? I guess it has something to do with specifying another lifetime, but I haven't been able to work out the correct approach, despite looking at The Book and a number of online resources.
It seems that the problem was with the Sum trait's lifetime parameter, and here is a solution without removing this trait
fn compute_mean_of_vec<'g, T>(input_vec: &'g Vec<T>) -> T
where
for<'x> T: Copy
+ num::Zero
+ std::ops::Add<T, Output = T>
+ std::ops::Div<T, Output = T>
+ num::FromPrimitive
+ std::iter::Sum<&'x T>,
{
let sum: T = input_vec.iter().sum();
sum / num::FromPrimitive::from_usize(input_vec.len()).unwrap()
}
fn normalise_cost_vec<'a, T>(cost_vec: &'a mut Vec<T>)
where
for<'x> T: std::ops::SubAssign
+ Copy
+ num::traits::identities::Zero
+ std::ops::Div<Output = T>
+ num::traits::cast::FromPrimitive
+ std::iter::Sum<&'x T>,
{
let mean = compute_mean_of_vec(cost_vec);
for c in cost_vec.iter_mut() {
*c -= mean;
}
}
fn main() {
let mut my_vec = vec![5.0f32; 5];
normalise_cost_vec(&mut my_vec);
for e in my_vec.iter() {
println!("{}", e);
}
}
i.e., by specifying an standalone lifetime parameter for the trait Sum, the parameter 'g won't be assumed to be carried along the whole function.
The problem is the Sum trait, let's look at its declaration:
pub trait Sum<A = Self> {
fn sum<I>(iter: I) -> Self
where
I: Iterator<Item = A>;
}
This means, that there is a reference bound to the function, that is valid to live even after the functions ends (theoretically). Therefore you get a "also borrowed as immutable" error.
The solution to this is now instead of using the Sum trait, you can use fold, because you already have a default value (num::Zero) and the Add trait required for your T.
fn compute_mean_of_vec<'g, T>(input_vec: &'g [T]) -> T
where
T: Copy
+ num::Zero
+ std::ops::Add<T, Output = T>
+ std::ops::Div<T, Output = T>
+ num::FromPrimitive,
{
let sum: T = input_vec.iter().fold(T::zero(), |a, e| a + *e);
sum / num::FromPrimitive::from_usize(input_vec.len()).unwrap()
}
fn normalise_cost_vec<'a, T>(cost_vec: &'a mut Vec<T>)
where
T: std::ops::SubAssign
+ Copy
+ num::traits::identities::Zero
+ std::ops::Div<Output = T>
+ num::traits::cast::FromPrimitive,
{
let mean = compute_mean_of_vec(cost_vec);
for c in cost_vec.iter_mut() {
*c -= mean;
}
}
(Playground)
The Solution I found is not to use std::iter::Sum and rewrite the sum call using fold:
fn compute_mean_of_vec<T>(input_vec: &[T]) -> T
where
T: Copy
+ num::Zero
+ std::ops::Add<T, Output = T>
+ std::ops::Div<T, Output = T>
+ num::FromPrimitive,
{
let sum: T = input_vec.into_iter().fold(T::zero(), |acc, &item| acc + item);
sum / num::FromPrimitive::from_usize(input_vec.len()).unwrap()
}
So you do not bind a mean value to the lifetime of input vec and compiler is happy.
I can't call Foo::new(words).split_first() in the following code
fn main() {
let words = "Sometimes think, the greatest sorrow than older";
/*
let foo = Foo::new(words);
let first = foo.split_first();
*/
let first = Foo::new(words).split_first();
println!("{}", first);
}
struct Foo<'a> {
part: &'a str,
}
impl<'a> Foo<'a> {
fn split_first(&'a self) -> &'a str {
self.part.split(',').next().expect("Could not find a ','")
}
fn new(s: &'a str) -> Self {
Foo { part: s }
}
}
the compiler will give me an error message
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:8:17
|
8 | let first = Foo::new(words).split_first();
| ^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
9 |
10 | println!("{}", first);
| ----- borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
If I bind the value of Foo::new(words) first, then call the split_first method there is no problem.
These two methods of calling should intuitively be the same but are somehow different.
Short answer: remove the 'a lifetime for the self parameter of split_first: fn split_first(&self) -> &'a str (playground).
Long answer:
When you write this code:
struct Foo<'a> {
part: &'a str,
}
impl<'a> Foo<'a> {
fn new(s: &'a str) -> Self {
Foo { part: s }
}
}
You are telling the compiler that all Foo instances are related to some lifetime 'a that must be equal to or shorter than the lifetime of the string passed as parameter to Foo::new. That lifetime 'a may be different from the lifetime of each Foo instance. When you then write:
let words = "Sometimes think, the greatest sorrow than older";
Foo::new(words)
The compiler infers that the lifetime 'a must be equal to or shorter than the lifetime of words. Barring any other constraints the compiler will use the lifetime of words, which is 'static so it is valid for the full life of the program.
When you add your definition of split_first:
fn split_first(&'a self) -> &'a str
You are adding an extra constraint: you are saying that 'a must also be equal to or shorter than the lifetime of self. The compiler will therefore take the shorter of the lifetime of words and the lifetime of the temporary Foo instance, which is the lifetime of the temporary. #AndersKaseorg's answer explains why that doesn't work.
By removing the 'a lifetime on the self parameter, I am decorrelating 'a from the lifetime of the temporary, so the compiler can again infer that 'a is the lifetime of words, which is long enough for the program to work.
Foo::new(words).split_first() would be interpreted roughly as
let tmp = Foo::new(words);
let ret = tmp.split_first();
drop(tmp);
ret
If Rust allowed you to do this, the references in ret would point [edit: would be allowed by the type of split_first to point*] into the now dropped value of tmp. So it’s a good thing that Rust disallows this. If you wrote the equivalent one-liner in C++, you’d silently get undefined behavior.
By writing the let binding yourself, you delay the drop until the end of the scope, thus extending the region where it’s safe to have these references.
For more details, see temporary lifetimes in the Rust Reference.
* Edit: As pointed out by Jmb, the real problem in this particular example is that the type
fn split_first(&'a self) -> &'a str
isn’t specific enough, and a better solution is to refine the type to:
fn split_first<'b>(&'b self) -> &'a str
which can be abbreviated:
fn split_first(&self) -> &'a str
This conveys the intended guarantee that the returned references do not point into the Foo<'a> (only into the string itself).
Despite thoroughly reading the documentation, I'm rather confused about the meaning of the & and * symbol in Rust, and more generally about what is a Rust reference exactly.
In this example, it seems to be similar to a C++ reference (that is, an address that is automatically dereferenced when used):
fn main() {
let c: i32 = 5;
let rc = &c;
let next = rc + 1;
println!("{}", next); // 6
}
However, the following code works exactly the same:
fn main() {
let c: i32 = 5;
let rc = &c;
let next = *rc + 1;
println!("{}", next); // 6
}
Using * to dereference a reference wouldn't be correct in C++. So I'd like to understand why this is correct in Rust.
My understanding so far, is that, inserting * in front of a Rust reference dereferences it, but the * is implicitly inserted anyway so you don't need to add it (while in C++, it's implicitly inserted and if you insert it you get a compilation error).
However, something like this doesn't compile:
fn main() {
let mut c: i32 = 5;
let mut next: i32 = 0;
{
let rc = &mut c;
next = rc + 1;
}
println!("{}", next);
}
error[E0369]: binary operation `+` cannot be applied to type `&mut i32`
--> src/main.rs:6:16
|
6 | next = rc + 1;
| ^^^^^^
|
= note: this is a reference to a type that `+` can be applied to; you need to dereference this variable once for this operation to work
= note: an implementation of `std::ops::Add` might be missing for `&mut i32`
But this works:
fn main() {
let mut c: i32 = 5;
let mut next: i32 = 0;
{
let rc = &mut c;
next = *rc + 1;
}
println!("{}", next); // 6
}
It seems that implicit dereferencing (a la C++) is correct for immutable references, but not for mutable references. Why is this?
Using * to dereference a reference wouldn't be correct in C++. So I'd like to understand why this is correct in Rust.
A reference in C++ is not the same as a reference in Rust. Rust's references are much closer (in usage, not in semantics) to C++'s pointers. With respect to memory representation, Rust's references often are just a single pointer, while C++'s references are supposed to be alternative names of the same object (and thus have no memory representation).
The difference between C++ pointers and Rust references is that Rust's references are never NULL, never uninitialized and never dangling.
The Add trait is implemented (see the bottom of the doc page) for the following pairs and all other numeric primitives:
&i32 + i32
i32 + &i32
&i32 + &i32
This is just a convenience thing the std-lib developers implemented. The compiler can figure out that a &mut i32 can be used wherever a &i32 can be used, but that doesn't work (yet?) for generics, so the std-lib developers would need to also implement the Add traits for the following combinations (and those for all primitives):
&mut i32 + i32
i32 + &mut i32
&mut i32 + &mut i32
&mut i32 + &i32
&i32 + &mut i32
As you can see that can get quite out of hand. I'm sure that will go away in the future. Until then, note that it's rather rare to end up with a &mut i32 and trying to use it in a mathematical expression.
This answer is for those looking for the basics (e.g. coming from Google).
From the Rust book's References and Borrowing:
fn main() {
let s1 = String::from("hello");
let len = calculate_length(&s1);
println!("The length of '{}' is {}.", s1, len);
}
fn calculate_length(s: &String) -> usize {
s.len()
}
These ampersands represent references, and they allow you to refer to some value without taking ownership of it [i.e. borrowing].
The opposite of referencing by using & is dereferencing, which is accomplished with the dereference operator, *.
And a basic example:
let x = 5;
let y = &x; //set y to a reference to x
assert_eq!(5, x);
assert_eq!(5, *y); // dereference y
If we tried to write assert_eq!(5, y); instead, we would get a compilation error can't compare `{integer}` with `&{integer}`.
(You can read more in the Smart Pointers chapter.)
And from Method Syntax:
Rust has a feature called automatic referencing and dereferencing. Calling methods is one of the few places in Rust that has this behavior.
Here’s how it works: when you call a method with object.something(), Rust automatically adds in &, &mut, or * so object matches the signature of the method. In other words, the following are the same:
p1.distance(&p2);
(&p1).distance(&p2);
From the docs for std::ops::Add:
impl<'a, 'b> Add<&'a i32> for &'b i32
impl<'a> Add<&'a i32> for i32
impl<'a> Add<i32> for &'a i32
impl Add<i32> for i32
It seems the binary + operator for numbers is implemented for combinations of shared (but not mutable) references of the operands and owned versions of the operands. It has nothing to do with automatic dereferencing.