How to automatically assign default values to tuple struct members
struct A(f64, i32);
fn main() {
let mut a: A; // expect a.0 = 0.0, a.1 = 0
// even below 2 line code doesn't compile
// a.0 = 1.2;
// a.1 = 3;
println!("{}, {}", a.0, a.1);
}
But I'm getting below error
error[E0381]: used binding `a` isn't initialized
--> src/main.rs:5:24
|
4 | let mut a: A; // expect a.0 = 0.0, a.1 = 0
| ----- binding declared here but left uninitialized
5 | println!("{}, {}", a.0, a.1);
| ^^^ `a.0` used here but it isn't initialized
|
Add #[derive(Default)] and initialize with A::default (or Default::default()):
#[derive(Default)]
struct A(f64, i32);
fn main() {
let mut a = A::default(); // expect a.0 = 0.0, a.1 = 0
println!("{}, {}", a.0, a.1);
}
Related
How do split a struct into separate read and write objects? I.e. The struct Foo has a member called bar which I want to have as a read-only reference in some part of the program (the readonly method), and I want to be able to simultaneously mutate bar in another part of the program (the main function).
I have the following scenario:
use futures::stream::StreamExt;
struct Foo {
bar: u8
}
impl Foo {
fn readonly(self: &Self) -> impl futures::stream::Stream<Item = u8> + '_ {
futures::stream::iter(0..10).map(|_x| {
self.bar
})
}
}
#[tokio::main]
async fn main() {
let mut foo = Foo {bar: 123u8};
let mut stream = foo.readonly();
let a = stream.next().await;
println!("a: {:?}", a);
foo.bar = 132;
let b = stream.next().await;
println!("b: {:?}", b);
}
which gives the compile error:
error[E0506]: cannot assign to `foo.bar` because it is borrowed
--> src/main.rs:23:5
|
18 | let mut stream = foo.readonly();
| -------------- borrow of `foo.bar` occurs here
...
23 | foo.bar = 132;
| ^^^^^^^^^^^^^ assignment to borrowed `foo.bar` occurs here
24 |
25 | let b = stream.next().await;
| ------------- borrow later used here
I tried to solve this by wrapping the struct in a Rc<RefCell<_>>:
use std::{cell::RefCell, rc::Rc};
use futures::stream::StreamExt;
struct Foo {
bar: u8
}
impl Foo {
fn readonly<'a>(self: &'a Self) -> impl futures::stream::Stream<Item = u8> + 'a {
futures::stream::iter(0..10).map(|_x| {
self.bar
})
}
}
#[tokio::main]
async fn main() {
let foo = Rc::new(RefCell::new(Foo {bar: 123u8}));
let foo_cloned = foo.clone();
let foo_borrowed = foo_cloned.borrow();
let mut stream = foo_borrowed.readonly();
let a = stream.next().await;
println!("a: {:?}", a);
foo.borrow_mut().bar = 0u8;
let b = stream.next().await;
println!("b: {:?}", b);
}
but this fails at runtime with:
a: Some(123)
thread 'main' panicked at 'already borrowed: BorrowMutError', src/main.rs:28:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
If I instead use unsafe code it works:
#[tokio::main]
async fn main() {
let foo = Rc::new(RefCell::new(Foo {bar: 123u8}));
let foo_cloned = foo.clone();
let foo_borrowed = foo_cloned.borrow();
let mut stream = foo_borrowed.readonly();
let a = stream.next().await;
println!("a: {:?}", a);
unsafe {
(*foo.as_ptr()).bar = 0u8;
}
let b = stream.next().await;
println!("b: {:?}", b);
}
output:
a: Some(123)
b: Some(0)
playground
is there a better, more specialized way to do this?
You almost got it, but you have to wrap only the part you care about in a Cell or RefCell, not the whole struct:
use std::cell::Cell;
use futures::stream::StreamExt;
struct Foo {
bar: Cell<u8>,
}
impl Foo {
fn readonly(self: &Self) -> impl futures::stream::Stream<Item = u8> + '_ {
futures::stream::iter(0..10).map(|_x| {
self.bar.get()
})
}
}
#[tokio::main]
async fn main() {
let mut foo = Foo {bar: Cell::new(123u8)};
let mut stream = foo.readonly();
let a = stream.next().await;
println!("a: {:?}", a);
foo.bar.set(132);
let b = stream.next().await;
println!("b: {:?}", b);
}
I am new to rust programming. I wanted to implement merge sort with recursion. Here is my code:
fn merge(a: &mut Vec<u32>, b: &mut Vec<u32>) -> Vec<u32> {
let mut temp: Vec<u32> = Vec::new();
println!("The digit is {}", a[0]);
while a.len() > 0 && b.len() > 0 {
if a[0] > b[0] {
temp.push(a[0]);
a.pop();
} else {
temp.push(b[0]);
b.pop();
}
}
while a.len() > 0 {
temp.push(a[0]);
a.pop();
}
while b.len() > 0 {
temp.push(b[0]);
b.pop();
}
temp
}
fn merge_sort(v: &mut Vec<u32>) -> Vec<u32> {
println!("The divided vector is: {:?}", v);
let n = v.len();
if n == 1 {
println!("The divided vector is: {:?}", v.to_vec());
let t: Vec<u32> = Vec::new();
t.push(v[0]);
t
}
if n == 0 {
panic!("Alas!! NULL");
}
merge(
&mut merge_sort(&mut v[0..n / 2].to_vec()),
&mut merge_sort(&mut v[n / 2 + 1..n].to_vec()),
)
.to_vec()
}
fn main() {
let mut v = vec![23, 78, 89, 64, 23, 12, 79, 45, 64];
println!("The vector is: {:?}", v);
println!("The length {}", v.len());
let v = merge_sort(&mut v);
println!("The sorted vector is: {:?}", v);
}
The problem is, when I am trying to compile it, I am getting the following error:
error[E0308]: mismatched types
--> src/main.rs:36:9
|
32 | / if n == 1 {
33 | | println!("The divided vector is: {:?}", v.to_vec());
34 | | let t: Vec<u32> = Vec::new();
35 | | t.push(v[0]);
36 | | t
| | ^ expected `()`, found struct `std::vec::Vec`
37 | | }
| | -- help: consider using a semicolon here
| |_____|
| expected this to be `()`
|
= note: expected unit type `()`
found struct `std::vec::Vec<u32>`
Do you have any idea why am I getting this strange error! It seems, I am missing something.
In Rust, the block type is the type of the final expression or () if there is none. Also combined blocks needs to be same type like if{...} else if{...} else{...}. Without an else the return type of an if expression must be () as this is the type that is returned when the expression evaluates to false.
Additionally the result is not the final expression in your code. What you need instead is to use return. Also be aware Vec::push requires a mutable reference of instance(&mut self).
if n == 1 {
println!("The divided vector is: {:?}", v.to_vec());
let mut t: Vec<u32> = Vec::new();
t.push(v[0]);
return t;
}
I'm trying to solve an exercise at the end of this chapter in the Rust Book.
Here is a code sample:
fn mean(v: &Vec<i32>) -> f64 {
let mut sum = 0.0;
let mut count = 0.0;
for val in v {
sum += &f64::from(val);
count += 1.0;
}
sum / count
}
fn main() {
let v = vec![1, 2, 3, 4];
println!("The mean is {}", mean(&v));
}
The error is:
error[E0277]: the trait bound `f64: std::convert::From<&i32>` is not satisfied
--> src/main.rs:6:17
|
6 | sum += &f64::from(val);
| ^^^^^^^^^ the trait `std::convert::From<&i32>` is not implemented for `f64`
|
= help: the following implementations were found:
<f64 as std::convert::From<f32>>
<f64 as std::convert::From<i16>>
<f64 as std::convert::From<i32>>
<f64 as std::convert::From<i8>>
and 3 others
= note: required by `std::convert::From::from`
I also tried using the as keyword but it didn't help.
f64 only implements From for i32, not &i32 (which is a reference to an i32). To get this to work, you will need to dereference val.
fn mean(v: &Vec<i32>) -> f64 {
let mut sum = 0.0;
let mut count = 0.0;
for val in v {
sum += f64::from(*val);
count += 1.0;
}
sum / count
}
The same applies if you try to do val as f64, and in fact, you get a much more helpful error message in that case:
error[E0606]: casting `&i32` as `f64` is invalid
--> src/main.rs:6:16
|
6 | sum += val as f64;
| ---^^^^^^^
| |
| cannot cast `&i32` as `f64`
| help: dereference the expression: `*val`
You can dereference the variable with *val as f64.
fn mean(v: &Vec<i32>) -> f64 {
let mut sum = 0.0;
let mut count = 0.0;
for val in v {
sum += *val as f64;
count += 1.0;
}
sum / count
}
fn main() {
let v = vec![1, 2, 3, 4];
println!("The mean is {}", mean(&v));
}
Another way to do it
fn main() {
let v = vec![1, 2, 3, 4];
let mean: f64 = v.iter().map(|&val| val as f64).sum::<f64>() / v.len() as f64;
println!("The mean is {}", mean);
}
When pattern-matching, you can specify that you'd like to get a mutable reference to the contained value by using ref mut:
let mut score = Some(42);
if let Some(ref mut s) = score {
&mut s;
}
However, the inner value is not mutable:
error[E0596]: cannot borrow immutable local variable `s` as mutable
--> src/main.rs:4:14
|
4 | &mut s;
| ^
| |
| cannot reborrow mutably
| try removing `&mut` here
I tried to add in another mut, but that was not valid:
if let Some(mut ref mut s) = score {
&mut s;
}
error: the order of `mut` and `ref` is incorrect
--> src/main.rs:3:17
|
3 | if let Some(mut ref mut s) = score {
| ^^^^^^^ help: try switching the order: `ref mut`
error: expected identifier, found keyword `mut`
--> src/main.rs:3:25
|
3 | if let Some(mut ref mut s) = score {
| ^^^ expected identifier, found keyword
error: expected one of `)`, `,`, or `#`, found `s`
--> src/main.rs:3:29
|
3 | if let Some(mut ref mut s) = score {
| ^ expected one of `)`, `,`, or `#` here
Not a direct answer, but possible workarounds
Create an intermediate variable
if let Some(ref mut s) = score {
let mut s = s;
&mut s;
}
#[derive(Debug)]
struct X;
enum Foo<T> {
Bar(T),
_Baz,
}
fn main() {
let mut score = Foo::Bar(X);
if let Foo::Bar(ref mut s) = score {
//let x = s;
//println!("{:?}", **x); ! not possible
let x = &mut &mut *s; // &mut &mut X
println!("{:?}", **x);
}
}
For Option specifically
if let Some(ref mut s) = score.as_mut() {
s; //:&mut &mut i32
}
if let Some(mut s) = score.as_mut() {
&mut s;
}
Below code may give an idea for the possible solution to the problem. It's just a sample & testable code to provide a tiny example that aimed at the issue. Of course it may not cover the whole intents and purposes.
fn main() {
let mut score = Some(42i32);
let res = if let Some(41) = score {
println!("41 is matched");
1i32
} else if let Some(ref mut s) = score { //&mut score {
//let mut s2 = s;
//println!("s: {:#?}", s);
test(&mut &mut *s); // This part may be like this for borrowing
//println!("s: {:#?}", s);
1i32
} else {
0i32
};
//println!("Result: {:#?}", score);
assert_eq!(res, 1i32);
}
fn test(ref mut s: &mut &mut i32) -> i32 {
//let mut s2 = s;
return test2(&mut *s);
}
fn test2(n: &mut i32) -> i32 {
*n += 1;
//println!("Value: {}", *(*n));
return *n;
}
Live Version: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7c3e7e1ee712a31f74b201149365035f
Gist Link: https://gist.github.com/7c3e7e1ee712a31f74b201149365035f
The following code fails to compile with the error below:
enum Test {
C(i32),
}
fn main() {
let mut v = Vec::new();
v.push(Test::C(0));
if let Some(Test::C(ref mut c)) = v.last_mut() {
*c = *c + 1;
}
}
error[E0308]: mismatched types
--> src/main.rs:10:17
|
10 | if let Some(Test::C(ref mut c)) = v.last_mut() {
| ^^^^^^^^^^^^^^^^^^ expected &mut Test, found enum `Test`
|
= note: expected type `&mut Test`
found type `Test`
last_mut() returns a mutable reference, and I'm taking the i32 as a mutable reference. I've tried making the mutability even more clear as follows, but I get the same compiler error.
if let Some(ref mut e) = v.last_mut() {
if let Test::C(ref mut c) = e {
*c = *c + 1;
}
}
Why doesn't this work?
You just need to match exactly what the error message says. It expects a &mut Test, so you should match on that:
if let Some(&mut Test::C(ref mut c)) = v.last_mut() {
// ^^^^^^
*c = *c + 1;
}
Here it is running in the playground.
As of Rust 1.26, your original code works as-is and the explicit ref and ref mut keywords are no longer required:
if let Some(Test::C(c)) = v.last_mut() {
*c = *c + 1;
}