How to make sense of the following piece of code? I'm new to Rust but have background on C/Haskell and a little bit C++. The only reference I can find is to deref coercions.
fn main() {
let xs: [u32; 4] = [0, 1, 2, 3];
let mut i: u32 = 0;
for x in xs.iter() {
if i > *x { // It looks x is an iterator. Understood.
i = i + x; // no error. (coerced)
//Quote: "Rust will do this as many times
// as possible until the types match."
i = i + *x; // no error (explicit deref)
i += x; // error about u32/&u32 mismatch. Why the magic failed?
i += *x; // no error (explicit deref)
}
}
println!("{}", i);
}
There is no auto-deref or coercion here, i + x works simply because u32 implements both Add<u32> and Add<&u32>. If you check the docs for u32, you'll find the following four trait impls:
impl Add<u32> for u32
impl<'a> Add<u32> for &'a u32
impl<'a> Add<&'a u32> for u32
impl<'a, 'b> Add<&'a u32> for &'b u32
u32 only implements AddAssign<u32> but not AddAssign<&u32> (this is a bug and will be fixed in 1.18 or 1.19 fixing it causes regression which means this impl probably needs to wait for Rust 2.0), so i += x is an error.
impl AddAssign<u32> for u32
//impl<'a> AddAssign<&'a u32> for u32 <-- is missing.
Why does auto-dereferencing not happen? — Auto-deref only happens when it is a receiver i.e. the "self" in a method call foo.bar(). x is not a "self" argument and + is not a method call. So there's no auto-deref here. See What are Rust's exact auto-dereferencing rules? for detail.
Related
How to make sense of the following piece of code? I'm new to Rust but have background on C/Haskell and a little bit C++. The only reference I can find is to deref coercions.
fn main() {
let xs: [u32; 4] = [0, 1, 2, 3];
let mut i: u32 = 0;
for x in xs.iter() {
if i > *x { // It looks x is an iterator. Understood.
i = i + x; // no error. (coerced)
//Quote: "Rust will do this as many times
// as possible until the types match."
i = i + *x; // no error (explicit deref)
i += x; // error about u32/&u32 mismatch. Why the magic failed?
i += *x; // no error (explicit deref)
}
}
println!("{}", i);
}
There is no auto-deref or coercion here, i + x works simply because u32 implements both Add<u32> and Add<&u32>. If you check the docs for u32, you'll find the following four trait impls:
impl Add<u32> for u32
impl<'a> Add<u32> for &'a u32
impl<'a> Add<&'a u32> for u32
impl<'a, 'b> Add<&'a u32> for &'b u32
u32 only implements AddAssign<u32> but not AddAssign<&u32> (this is a bug and will be fixed in 1.18 or 1.19 fixing it causes regression which means this impl probably needs to wait for Rust 2.0), so i += x is an error.
impl AddAssign<u32> for u32
//impl<'a> AddAssign<&'a u32> for u32 <-- is missing.
Why does auto-dereferencing not happen? — Auto-deref only happens when it is a receiver i.e. the "self" in a method call foo.bar(). x is not a "self" argument and + is not a method call. So there's no auto-deref here. See What are Rust's exact auto-dereferencing rules? for detail.
Say I have the following,
use std::io;
use std::io::Read;
#[derive(Debug)]
enum FooReadError {
UnexpectedEof,
IoError(io::Error),
}
impl From<io::Error> for FooReadError {
fn from(err: io::Error) -> FooReadError {
FooReadError::IoError(err)
}
}
fn read_n_bytes_to_vector<R: Read>(reader: &mut R, length: usize)
-> Result<Vec<u8>, FooReadError> {
let mut bytes = Vec::<u8>::with_capacity(length);
unsafe { bytes.set_len(length); }
let bytes_read = try!(reader.read(&mut bytes[..]));
if bytes_read != length {
Err(FooReadError::UnexpectedEof)
} else {
Ok(bytes)
}
}
fn do_some_read(reader: &mut Read) -> Vec<u8> {
read_n_bytes_to_vector(reader, 16).unwrap()
}
fn main() {
let v = vec![0, 1, 2, 3, 4, 5];
let mut cur = io::Cursor::<Vec<u8>>::new(v);
do_some_read(&mut cur);
}
The read_n_bytes_to_vector is supposed to take anything implementing the trait io::Read, read length bytes from it, and put them into a vector and return the vector.
The function do_some_read has a io::Read trait object. So, why then:
% rustc ./vec_read.rs
./vec_read.rs:29:5: 29:27 error: the trait `core::marker::Sized` is not implemented for the type `std::io::Read` [E0277]
./vec_read.rs:29 read_n_bytes_to_vector(reader, 16).unwrap()
^~~~~~~~~~~~~~~~~~~~~~
./vec_read.rs:29:5: 29:27 note: `std::io::Read` does not have a constant size known at compile-time
./vec_read.rs:29 read_n_bytes_to_vector(reader, 16).unwrap()
^~~~~~~~~~~~~~~~~~~~~~
I agree with the compiler that io::Read can't possibly implement Sized; but I'm passing a trait object — those are constant-size, so it should be okay here; **so why the error?* But wait, why does it even matter? The function isn't taking an io::Read for an arg (right?), it's taking a trait object too, because the arg is generic, and should take the full type of what's passed in.
Generics include the Sized bound by default; if you do not wish it to be required, you must add the ?Sized bound.
A trait object is not of constant size; u16 as Trait is two bytes, u32 as Trait is four bytes, &c.; only things like boxed trait objects (Box<Trait>) and trait object references (&Trait, &mut Trait) have a constant size, known at compile time (two words for the cited examples).
Because you only use an R by mutable reference, you can add the ?Sized bound successfully:
fn read_n_bytes_to_vector<R: ?Sized + Read>(reader: &mut R, length: usize)
-> Result<Vec<u8>, FooReadError> {
I am trying to understand Rust's reference.
fn main() {
let x: i32 = 0;
println!("{}", x+1); // this works
println!("{}", (&x)+1); // this works
//println!("{}", (&(&x))+1); // but this failed
}
What I get:
1
1
What does & actually do? Why can &x be added like it is an integer but not &(&x)?
& takes the reference of the operand. This can be thought of as finding the memory address that the value is stored at.
Your example works because + is implemented using the Add trait, which has the following variants:
impl Add<i32> for i32
impl<'a> Add<i32> for &'a i32
impl<'a> Add<&'a i32> for i32
impl<'a, 'b> Add<&'a i32> for &'b i32
That is, you can add any pair of references and non-references. However, your second example would have two levels of indirection (&&i32), and the Add trait isn't implemented for that many levels of reference.
In Rust, when we want a struct to contain references, we typically define their lifetimes as such:
struct Foo<'a> {
x: &'a i32,
y: &'a i32,
}
But it's also possible to define multiple lifetimes for different references in the same struct:
struct Foo<'a, 'b> {
x: &'a i32,
y: &'b i32,
}
When is it ever useful to do this? Can someone provide some example code that doesn't compile when both lifetimes are 'a but does compile when the lifetimes are 'a and 'b (or vice versa)?
After staying up way too late, I was able to come up with an example case where the lifetimes matter. Here is the code:
static ZERO: i32 = 0;
struct Foo<'a, 'b> {
x: &'a i32,
y: &'b i32,
}
fn get_x_or_zero_ref<'a, 'b>(x: &'a i32, y: &'b i32) -> &'a i32 {
if *x > *y {
return x
} else {
return &ZERO
}
}
fn main() {
let x = 1;
let v;
{
let y = 2;
let f = Foo { x: &x, y: &y };
v = get_x_or_zero_ref(&f.x, &f.y);
}
println!("{}", *v);
}
If you were to change the definition of Foo to this:
struct Foo<'a> {
x: &'a i32,
y: &'a i32,
}
Then the code won't compile.
Basically, if you want to use the fields of the struct on any function that requires it's parameters to have different lifetimes, then the fields of the struct must have different lifetimes as well.
I want to re-answer my question here since it's still showing up high in search results and I feel I can explain better. Consider this code:
Rust Playground
struct Foo<'a> {
x: &'a i32,
y: &'a i32,
}
fn main() {
let x = 1;
let v;
{
let y = 2;
let f = Foo { x: &x, y: &y };
v = f.x;
}
println!("{}", *v);
}
And the error:
error[E0597]: `y` does not live long enough
--> src/main.rs:11:33
|
11 | let f = Foo { x: &x, y: &y };
| ^^ borrowed value does not live long enough
12 | v = f.x;
13 | }
| - `y` dropped here while still borrowed
14 | println!("{}", *v);
| -- borrow later used here
What's going on here?
The lifetime of f.x has the requirement of being at least large enough to encompass the scope of x up until the println! statement (since it's initialized with &x and then assigned to v).
The definition of Foo specifies that both f.x and f.y use the same generic lifetime 'a, so the lifetime of f.y must be at least as large as f.x.
But, that can't work, because we assign &y to f.y, and y goes out of scope before the println!. Error!
The solution here is to allow Foo to use separate lifetimes for f.x and f.y, which we do using multiple generic lifetime parameters:
Rust Playground
struct Foo<'a, 'b> {
x: &'a i32,
y: &'b i32,
}
Now the lifetimes of f.x and f.y aren't tied together. The compiler will still use a lifetime that's valid until the println! statement for f.x. But there's no longer a requirement that f.y uses the same lifetime, so the compiler is free to choose a smaller lifetime for f.y, such as one that is valid only for the scope of y.
Here is another simple example where the struct definition has to use two lifetimes in order to operate as expected. It does not split the aggregate into fields of different lifetimes, but nests the struct with another struct.
struct X<'a>(&'a i32);
struct Y<'a, 'b>(&'a X<'b>);
fn main() {
let z = 100;
//taking the inner field out of a temporary
let z1 = ((Y(&X(&z))).0).0;
assert!(*z1 == z);
}
The struct Y has two lifetime parameters, one for its contained field &X, and one for X's contained field &z.
In the operation ((Y(&X(&z))).0).0, X(&z) is created as a temporary and is borrowed. Its lifetime is only in the scope of this operation, expiring at the statement end. But since X(&z)'s lifetime is different from the its contained field &z, the operation is fine to return &z, whose value can be accessed later in the function.
If using single lifetime for Y struct. This operation won't work, because the lifetime of &z is the same as its containing struct X(&z), expiring at the statement end; therefore the returned &z is no longer valid to be accessed afterwards.
See code in the playground.
I've been working on a multi-dimensional array library, toying around with different interfaces, and ran into an issue I can't seem to solve. This may be a simple misunderstanding of lifetimes, but I've tried just about every solution I can think of, to no success.
The goal: implement the Index and IndexMut traits to return a borrowed vector from a 2d matrix, so this syntax can be used mat[rowind][colind].
A (very simplified) version of the data structure definition is below.
pub struct Matrix<T> {
shape: [uint, ..2],
dat: Vec<T>
}
impl<T: FromPrimitive+Clone> Matrix<T> {
pub fn new(shape: [uint, ..2]) -> Matrix<T> {
let size = shape.iter().fold(1, |a, &b| { a * b});
// println!("Creating MD array of size: {} and shape: {}", size, shape)
Matrix{
shape: shape,
dat: Vec::<T>::from_elem(size, FromPrimitive::from_uint(0u).expect("0 must be convertible to parameter type"))
}
}
pub fn mut_index(&mut self, index: uint) -> &mut [T] {
let base = index*self.shape[1];
self.dat.mut_slice(base, base + self.shape[1])
}
}
fn main(){
let mut m = Matrix::<f32>::new([4u,4]);
println!("{}", m.dat)
println!("{}", m.mut_index(3)[0])
}
The mut_index method works exactly as I would like the IndexMut trait to work, except of course that it doesn't have the syntax sugar. The first attempt at implementing IndexMut made me wonder, since it returns a borrowed reference to the specified type, I really want to specify [T] as a type, but it isn't a valid type. So the only option is to specify &mut [T] like this.
impl<T: FromPrimitive+Clone> IndexMut<uint, &mut [T]> for Matrix<T> {
fn index_mut(&mut self, index: &uint) -> &mut(&mut[T]) {
let base = index*self.shape[1];
&mut self.dat.mut_slice(base, base + self.shape[1])
}
}
This complains about a missing lifetime specifier on the trait impl line. So I try adding one.
impl<'a, T: FromPrimitive+Clone> IndexMut<uint, &'a mut [T]> for Matrix<T> {
fn index_mut(&'a mut self, index: &uint) -> &mut(&'a mut[T]) {
let base = index*self.shape[1];
&mut self.dat.mut_slice(base, base + self.shape[1])
}
}
Now I get method `index_mut` has an incompatible type for trait: expected concrete lifetime, but found bound lifetime parameter 'a [E0053]. Aside from this I've tried just about every combination of one and two lifetimes I can think of, as well as creating a secondary structure to hold a reference that is stored in the outer structure during the indexing operation so a reference to that can be returned instead, but that's not possible for Index. The final answer may just be that this isn't possible, given the response on this old github issue, but that would seem to be a problematic limitation of the Index and IndexMut traits. Is there something I'm missing?
At present, this is not possible, but when Dynamically Sized Types lands I believe it will become possible.
Let’s look at the signature:
pub trait IndexMut<Index, Result> {
fn index_mut<'a>(&'a mut self, index: &Index) -> &'a mut Result;
}
(Note the addition of the <'a> compared with what the docs say; I’ve filed #16228 about that.)
'a is an arbitrary lifetime, but it is important that it is specified on the method, not on the impl as a whole: it is in absolute truth a generic parameter to the method. I’ll show how it all comes out here with the names 'ρ₀ and 'ρ₁. So then, in this attempt:
impl<'ρ₀, T: FromPrimitive + Clone> IndexMut<uint, &'ρ₀ mut [T]> for Matrix<T> {
fn index_mut<'ρ₁>(&'ρ₁ mut self, index: &uint) -> &'ρ₁ mut &'ρ₀ mut [T] {
let base = index * self.shape[1];
&mut self.dat.mut_slice(base, base + self.shape[1])
}
}
This satisfies the requirements that (a) all lifetimes must be explicit in the impl header, and (b) that the method signature matches the trait definition: Index is uint and Result is &'ρ₀ mut [T]. Because 'ρ₀ is defined on the impl block (so that it can be used as a parameter there) and 'ρ₁ on the method (because that’s what the trait defines), 'ρ₀ and 'ρ₁ cannot be combined into a single named lifetime. (You could call them both 'a, but this is shadowing and does not change anything except for the introduction of a bit more confusion!)
However, this is not enough to have it all work, and it will indeed not compile, because 'ρ₀ is not tied to anything, nor is there to tie it to in the signature. And so you cannot cast self.data.mut_slice(…), which is of type &'ρ₁ mut [T], to &'ρ₀ mut [T] as the lifetimes do not match, nor is there any known subtyping relationship between them (that is, it cannot structurally be demonstrated that the lifetime 'ρ₀ is less than—a subtype of—'ρ₁; although the return type of the method would make that clear, it is not so at the basic type level, and so it is not permitted).
Now as it happens, IndexMut isn’t as useful as it should be anyway owing to #12825, as matrix[1] would always use IndexMut and never Index if you have implemented both. I’m not sure if that’s any consolation, though!
The solution comes in Dynamically Sized Types. When that is here, [T] will be a legitimate unsized type which can be used as the type for Result and so this will be the way to write it:
impl<T: FromPrimitive + Clone> IndexMut<uint, [T]> for Matrix<T> {
fn index_mut<'a>(&'a mut self, index: &uint) -> &'a mut [T] {
let base = index * self.shape[1];
&mut self.dat.mut_slice(base, base + self.shape[1])
}
}
… but that’s not here yet.
This code works in Rust 1.25.0 (and probably has for quite a while)
extern crate num;
use num::Zero;
pub struct Matrix<T> {
shape: [usize; 2],
dat: Vec<T>,
}
impl<T: Zero + Clone> Matrix<T> {
pub fn new(shape: [usize; 2]) -> Matrix<T> {
let size = shape.iter().product();
Matrix {
shape: shape,
dat: vec![T::zero(); size],
}
}
pub fn mut_index(&mut self, index: usize) -> &mut [T] {
let base = index * self.shape[1];
&mut self.dat[base..][..self.shape[1]]
}
}
fn main() {
let mut m = Matrix::<f32>::new([4; 2]);
println!("{:?}", m.dat);
println!("{}", m.mut_index(3)[0]);
}
You can enhance it to support Index and IndexMut:
use std::ops::{Index, IndexMut};
impl<T> Index<usize> for Matrix<T> {
type Output = [T];
fn index(&self, index: usize) -> &[T] {
let base = index * self.shape[1];
&self.dat[base..][..self.shape[1]]
}
}
impl<T> IndexMut<usize> for Matrix<T> {
fn index_mut(&mut self, index: usize) -> &mut [T] {
let base = index * self.shape[1];
&mut self.dat[base..][..self.shape[1]]
}
}
fn main() {
let mut m = Matrix::<f32>::new([4; 2]);
println!("{:?}", m.dat);
println!("{}", m[3][0]);
m[3][0] = 42.42;
println!("{:?}", m.dat);
println!("{}", m[3][0]);
}